self._check_self()
for s in self.subsystems:
self.remove_subsystem(s)
+ for r in self.referrals:
+ r.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
def setup(cls, root, n, err_func):
'''
port._setup_attrs(n, err_func)
for s in n.get('subsystems', []):
port.add_subsystem(s)
+ for r in n.get('referrals', []):
+ Referral.setup(port, r, err_func)
def dump(self):
d = super(Port, self).dump()
d['portid'] = self.portid
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
h.delete()
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):
root = nvme.Root()
def __init__(self, parent, cfnode):
UINode.__init__(self, str(cfnode.portid), parent, cfnode)
UIPortSubsystemsNode(self)
+ UIReferralsNode(self)
def status(self):
if self.cfnode.get_enable():
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):
def __init__(self, parent):
UINode.__init__(self, 'hosts', parent)