|
Packit |
01965a |
#!/usr/bin/python
|
|
Packit |
01965a |
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Frontend to access to the NVMe target configfs hierarchy
|
|
Packit |
01965a |
|
|
Packit |
01965a |
Copyright (c) 2016 by HGST, a Western Digital Company.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
Packit |
01965a |
not use this file except in compliance with the License. You may obtain
|
|
Packit |
01965a |
a copy of the License at
|
|
Packit |
01965a |
|
|
Packit |
01965a |
http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
01965a |
|
|
Packit |
01965a |
Unless required by applicable law or agreed to in writing, software
|
|
Packit |
01965a |
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
Packit |
01965a |
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
Packit |
01965a |
License for the specific language governing permissions and limitations
|
|
Packit |
01965a |
under the License.
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
|
|
Packit |
01965a |
from __future__ import print_function
|
|
Packit |
01965a |
|
|
Packit |
01965a |
import os
|
|
Packit |
01965a |
import sys
|
|
Packit |
01965a |
import configshell_fb as configshell
|
|
Packit |
01965a |
import nvmet as nvme
|
|
Packit |
01965a |
from string import hexdigits
|
|
Packit |
01965a |
import uuid
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ngiud_set(nguid):
|
|
Packit |
01965a |
return any(c in hexdigits and c != '0' for c in nguid)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UINode(configshell.node.ConfigNode):
|
|
Packit |
01965a |
def __init__(self, name, parent=None, cfnode=None, shell=None):
|
|
Packit |
01965a |
configshell.node.ConfigNode.__init__(self, name, parent, shell)
|
|
Packit |
01965a |
self.cfnode = cfnode
|
|
Packit |
01965a |
if self.cfnode:
|
|
Packit |
01965a |
if self.cfnode.attr_groups:
|
|
Packit |
01965a |
for group in self.cfnode.attr_groups:
|
|
Packit |
01965a |
self._init_group(group)
|
|
Packit |
01965a |
self.refresh()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def _init_group(self, group):
|
|
Packit |
01965a |
setattr(self.__class__, "ui_getgroup_%s" % group,
|
|
Packit |
01965a |
lambda self, attr:
|
|
Packit |
01965a |
self.cfnode.get_attr(group, attr))
|
|
Packit |
01965a |
setattr(self.__class__, "ui_setgroup_%s" % group,
|
|
Packit |
01965a |
lambda self, attr, value:
|
|
Packit |
01965a |
self.cfnode.set_attr(group, attr, value))
|
|
Packit |
01965a |
|
|
Packit |
01965a |
attrs = self.cfnode.list_attrs(group)
|
|
Packit |
01965a |
attrs_ro = self.cfnode.list_attrs(group, writable=False)
|
|
Packit |
01965a |
for attr in attrs:
|
|
Packit |
01965a |
writable = attr not in attrs_ro
|
|
Packit |
01965a |
|
|
Packit |
01965a |
name = "ui_desc_%s" % group
|
|
Packit |
01965a |
t, d = getattr(self.__class__, name, {}).get(attr, ('string', ''))
|
|
Packit |
01965a |
self.define_config_group_param(group, attr, t, d, writable)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def refresh(self):
|
|
Packit |
01965a |
self._children = set([])
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def status(self):
|
|
Packit |
01965a |
return "None"
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_refresh(self):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Refreshes and updates the objects tree from the current path.
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
self.refresh()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_status(self):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Displays the current node's status summary.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{ls}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
self.shell.log.info("Status for %s: %s" % (self.path, self.status()))
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_saveconfig(self, savefile=None):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Saves the current configuration to a file so that it can be restored
|
|
Packit |
01965a |
on next boot.
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
node = self
|
|
Packit |
01965a |
while node.parent is not None:
|
|
Packit |
01965a |
node = node.parent
|
|
Packit |
01965a |
node.cfnode.save_to_file(savefile)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UIRootNode(UINode):
|
|
Packit |
01965a |
def __init__(self, shell):
|
|
Packit |
01965a |
UINode.__init__(self, '/', parent=None, cfnode=nvme.Root(),
|
|
Packit |
01965a |
shell=shell)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def refresh(self):
|
|
Packit |
01965a |
self._children = set([])
|
|
Packit |
01965a |
UISubsystemsNode(self)
|
|
Packit |
01965a |
UIPortsNode(self)
|
|
Packit |
01965a |
UIHostsNode(self)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_restoreconfig(self, savefile=None, clear_existing=False):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Restores configuration from a file.
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
errors = self.cfnode.restore_from_file(savefile, clear_existing)
|
|
Packit |
01965a |
self.refresh()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
if errors:
|
|
Packit |
01965a |
raise configshell.ExecutionError(
|
|
Packit |
01965a |
"Configuration restored, %d errors:\n%s" %
|
|
Packit |
01965a |
(len(errors), "\n".join(errors)))
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UISubsystemsNode(UINode):
|
|
Packit |
01965a |
def __init__(self, parent):
|
|
Packit |
01965a |
UINode.__init__(self, 'subsystems', parent)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def refresh(self):
|
|
Packit |
01965a |
self._children = set([])
|
|
Packit |
01965a |
for subsys in self.parent.cfnode.subsystems:
|
|
Packit |
01965a |
UISubsystemNode(self, subsys)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_create(self, nqn=None):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Creates a new target. If I{nqn} is ommited, then the new Subsystem
|
|
Packit |
01965a |
will be created using a randomly generated NQN.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{delete}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
subsystem = nvme.Subsystem(nqn, mode='create')
|
|
Packit |
01965a |
UISubsystemNode(self, subsystem)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_delete(self, nqn):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Recursively deletes the subsystem with the specified I{nqn}, and all
|
|
Packit |
01965a |
objects hanging under it.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{create}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
subsystem = nvme.Subsystem(nqn, mode='lookup')
|
|
Packit |
01965a |
subsystem.delete()
|
|
Packit |
01965a |
self.refresh()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UISubsystemNode(UINode):
|
|
Packit |
01965a |
ui_desc_attr = {
|
|
Packit |
01965a |
'allow_any_host': ('string', 'Allow access by any host if set to 1'),
|
|
Packit |
01965a |
'serial': ('string', 'Export serial number to hosts'),
|
|
Packit |
01965a |
'version': ('string', 'Export version number to hosts'),
|
|
Packit |
01965a |
}
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def __init__(self, parent, cfnode):
|
|
Packit |
01965a |
UINode.__init__(self, cfnode.nqn, parent, cfnode)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def refresh(self):
|
|
Packit |
01965a |
self._children = set([])
|
|
Packit |
01965a |
UINamespacesNode(self)
|
|
Packit |
01965a |
UIAllowedHostsNode(self)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def summary(self):
|
|
Packit |
01965a |
info = []
|
|
Packit |
01965a |
info.append("version=" + self.cfnode.get_attr("attr","version"))
|
|
Packit |
01965a |
info.append("allow_any=" + self.cfnode.get_attr("attr","allow_any_host"))
|
|
Packit |
01965a |
info.append("serial=" + self.cfnode.get_attr("attr","serial"))
|
|
Packit |
01965a |
return (", ".join(info), True)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UINamespacesNode(UINode):
|
|
Packit |
01965a |
def __init__(self, parent):
|
|
Packit |
01965a |
UINode.__init__(self, 'namespaces', parent)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def refresh(self):
|
|
Packit |
01965a |
self._children = set([])
|
|
Packit |
01965a |
for ns in self.parent.cfnode.namespaces:
|
|
Packit |
01965a |
UINamespaceNode(self, ns)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_create(self, nsid=None):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Creates a new namespace. If I{nsid} is ommited, then the next
|
|
Packit |
01965a |
available namespace id will be used.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{delete}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
namespace = nvme.Namespace(self.parent.cfnode, nsid, mode='create')
|
|
Packit |
01965a |
UINamespaceNode(self, namespace)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_delete(self, nsid):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Recursively deletes the namespace with the specified I{nsid}, and all
|
|
Packit |
01965a |
objects hanging under it.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{create}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
namespace = nvme.Namespace(self.parent.cfnode, nsid, mode='lookup')
|
|
Packit |
01965a |
namespace.delete()
|
|
Packit |
01965a |
self.refresh()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UINamespaceNode(UINode):
|
|
Packit |
01965a |
ui_desc_device = {
|
|
Packit |
01965a |
'path': ('string', 'Backing device path.'),
|
|
Packit |
01965a |
'nguid': ('string', 'Namspace Global Unique Identifier.'),
|
|
Packit |
01965a |
'uuid': ('string', 'Namespace Universally Unique Identifier.'),
|
|
Packit |
01965a |
}
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def __init__(self, parent, cfnode):
|
|
Packit |
01965a |
UINode.__init__(self, str(cfnode.nsid), parent, cfnode)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def status(self):
|
|
Packit |
01965a |
if self.cfnode.get_enable():
|
|
Packit |
01965a |
return "enabled"
|
|
Packit |
01965a |
return "disabled"
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_enable(self):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Enables the current Namespace.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{disable}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
if self.cfnode.get_enable():
|
|
Packit |
01965a |
self.shell.log.info("The Namespace is already enabled.")
|
|
Packit |
01965a |
else:
|
|
Packit |
01965a |
try:
|
|
Packit |
01965a |
self.cfnode.set_enable(1)
|
|
Packit |
01965a |
self.shell.log.info("The Namespace has been enabled.")
|
|
Packit |
01965a |
except Exception as e:
|
|
Packit |
01965a |
raise configshell.ExecutionError(
|
|
Packit |
01965a |
"The Namespace could not be enabled.")
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_disable(self):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Disables the current Namespace.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{enable}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
if not self.cfnode.get_enable():
|
|
Packit |
01965a |
self.shell.log.info("The Namespace is already disabled.")
|
|
Packit |
01965a |
else:
|
|
Packit |
01965a |
try:
|
|
Packit |
01965a |
self.cfnode.set_enable(0)
|
|
Packit |
01965a |
self.shell.log.info("The Namespace has been disabled.")
|
|
Packit |
01965a |
except Exception as e:
|
|
Packit |
01965a |
raise configshell.ExecutionError(
|
|
Packit |
01965a |
"The Namespace could not be disabled.")
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def summary(self):
|
|
Packit |
01965a |
info = []
|
|
Packit |
01965a |
info.append("path=" + self.cfnode.get_attr("device", "path"))
|
|
Packit |
01965a |
ns_uuid = self.cfnode.get_attr("device", "uuid")
|
|
Packit |
01965a |
if uuid.UUID(ns_uuid).int != 0:
|
|
Packit |
01965a |
info.append("uuid=" + str(ns_uuid))
|
|
Packit |
01965a |
ns_nguid = self.cfnode.get_attr("device", "nguid")
|
|
Packit |
01965a |
if ngiud_set(ns_nguid):
|
|
Packit |
01965a |
info.append("nguid=" + ns_nguid)
|
|
Packit |
01965a |
info.append("enabled" if self.cfnode.get_enable() else "disabled")
|
|
Packit |
01965a |
ns_enabled = self.cfnode.get_enable()
|
|
Packit |
01965a |
return (", ".join(info), True if ns_enabled == 1 else ns_enabled)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UIAllowedHostsNode(UINode):
|
|
Packit |
01965a |
def __init__(self, parent):
|
|
Packit |
01965a |
UINode.__init__(self, 'allowed_hosts', parent)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def refresh(self):
|
|
Packit |
01965a |
self._children = set([])
|
|
Packit |
01965a |
for host in self.parent.cfnode.allowed_hosts:
|
|
Packit |
01965a |
UIAllowedHostNode(self, host)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_create(self, nqn):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Grants access to parent subsystems to the host specified by I{nqn}.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{delete}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
self.parent.cfnode.add_allowed_host(nqn)
|
|
Packit |
01965a |
UIAllowedHostNode(self, nqn)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_complete_create(self, parameters, text, current_param):
|
|
Packit |
01965a |
completions = []
|
|
Packit |
01965a |
if current_param == 'nqn':
|
|
Packit |
01965a |
for host in self.get_node('/hosts').children:
|
|
Packit |
01965a |
completions.append(host.cfnode.nqn)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
if len(completions) == 1:
|
|
Packit |
01965a |
return [completions[0] + ' ']
|
|
Packit |
01965a |
else:
|
|
Packit |
01965a |
return completions
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_delete(self, nqn):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Recursively deletes the namespace with the specified I{nsid}, and all
|
|
Packit |
01965a |
objects hanging under it.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{create}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
self.parent.cfnode.remove_allowed_host(nqn)
|
|
Packit |
01965a |
self.refresh()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_complete_delete(self, parameters, text, current_param):
|
|
Packit |
01965a |
completions = []
|
|
Packit |
01965a |
if current_param == 'nqn':
|
|
Packit |
01965a |
for nqn in self.parent.cfnode.allowed_hosts:
|
|
Packit |
01965a |
completions.append(nqn)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
if len(completions) == 1:
|
|
Packit |
01965a |
return [completions[0] + ' ']
|
|
Packit |
01965a |
else:
|
|
Packit |
01965a |
return completions
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UIAllowedHostNode(UINode):
|
|
Packit |
01965a |
def __init__(self, parent, nqn):
|
|
Packit |
01965a |
UINode.__init__(self, nqn, parent)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UIPortsNode(UINode):
|
|
Packit |
01965a |
def __init__(self, parent):
|
|
Packit |
01965a |
UINode.__init__(self, 'ports', parent)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def refresh(self):
|
|
Packit |
01965a |
self._children = set([])
|
|
Packit |
01965a |
for port in self.parent.cfnode.ports:
|
|
Packit |
01965a |
UIPortNode(self, port)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_create(self, portid=None):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Creates a new NVMe port with portid I{portid}.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{delete}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
port = nvme.Port(portid, mode='create')
|
|
Packit |
01965a |
UIPortNode(self, port)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_delete(self, portid):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Recursively deletes the NVMe Port with the specified I{port}, and all
|
|
Packit |
01965a |
objects hanging under it.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{create}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
port = nvme.Port(portid, mode='lookup')
|
|
Packit |
01965a |
port.delete()
|
|
Packit |
01965a |
self.refresh()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UIPortNode(UINode):
|
|
Packit |
01965a |
ui_desc_addr = {
|
|
Packit |
01965a |
'adrfam': ('string', 'Address Family (e.g. ipv4 or fc)'),
|
|
Packit |
01965a |
'treq': ('string', 'Transport Security Requirements'),
|
|
Packit |
01965a |
'traddr': ('string', 'Transport Address (e.g. IP Address or FC wwnn:wwpn)'),
|
|
Packit |
01965a |
'trsvcid': ('string', 'Transport Service ID (e.g. IP Port)'),
|
|
Packit |
01965a |
'trtype': ('string', 'Transport Type (e.g. rdma or loop or fc)'),
|
|
Packit |
01965a |
}
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def __init__(self, parent, cfnode):
|
|
Packit |
01965a |
UINode.__init__(self, str(cfnode.portid), parent, cfnode)
|
|
Packit |
01965a |
UIPortSubsystemsNode(self)
|
|
Packit |
01965a |
UIReferralsNode(self)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def summary(self):
|
|
Packit |
01965a |
info = []
|
|
Packit |
01965a |
info.append("trtype=" + self.cfnode.get_attr("addr", "trtype"))
|
|
Packit |
01965a |
info.append("traddr=" + self.cfnode.get_attr("addr", "traddr"))
|
|
Packit |
01965a |
trsvcid = self.cfnode.get_attr("addr", "trsvcid")
|
|
Packit |
01965a |
if trsvcid != "none":
|
|
Packit |
01965a |
info.append("trsvcid=%s" % trsvcid)
|
|
Packit |
01965a |
enabled = not (not self.cfnode.subsystems and not list(self.cfnode.referrals))
|
|
Packit |
01965a |
return (", ".join(info), True if enabled else 0)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UIPortSubsystemsNode(UINode):
|
|
Packit |
01965a |
def __init__(self, parent):
|
|
Packit |
01965a |
UINode.__init__(self, 'subsystems', parent)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def refresh(self):
|
|
Packit |
01965a |
self._children = set([])
|
|
Packit |
01965a |
for host in self.parent.cfnode.subsystems:
|
|
Packit |
01965a |
UIPortSubsystemNode(self, host)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_create(self, nqn):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Grants access to the subsystem specified by I{nqn} through the
|
|
Packit |
01965a |
parent port.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{delete}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
self.parent.cfnode.add_subsystem(nqn)
|
|
Packit |
01965a |
UIPortSubsystemNode(self, nqn)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_complete_create(self, parameters, text, current_param):
|
|
Packit |
01965a |
completions = []
|
|
Packit |
01965a |
if current_param == 'nqn':
|
|
Packit |
01965a |
for subsys in self.get_node('/subsystems').children:
|
|
Packit |
01965a |
completions.append(subsys.cfnode.nqn)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
if len(completions) == 1:
|
|
Packit |
01965a |
return [completions[0] + ' ']
|
|
Packit |
01965a |
else:
|
|
Packit |
01965a |
return completions
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_delete(self, nqn):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Removes access to the subsystem specified by I{nqn} through the
|
|
Packit |
01965a |
parent port.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{create}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
self.parent.cfnode.remove_subsystem(nqn)
|
|
Packit |
01965a |
self.refresh()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_complete_delete(self, parameters, text, current_param):
|
|
Packit |
01965a |
completions = []
|
|
Packit |
01965a |
if current_param == 'nqn':
|
|
Packit |
01965a |
for nqn in self.parent.cfnode.subsystems:
|
|
Packit |
01965a |
completions.append(nqn)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
if len(completions) == 1:
|
|
Packit |
01965a |
return [completions[0] + ' ']
|
|
Packit |
01965a |
else:
|
|
Packit |
01965a |
return completions
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UIPortSubsystemNode(UINode):
|
|
Packit |
01965a |
def __init__(self, parent, nqn):
|
|
Packit |
01965a |
UINode.__init__(self, nqn, parent)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UIReferralsNode(UINode):
|
|
Packit |
01965a |
def __init__(self, parent):
|
|
Packit |
01965a |
UINode.__init__(self, 'referrals', parent)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def refresh(self):
|
|
Packit |
01965a |
self._children = set([])
|
|
Packit |
01965a |
for r in self.parent.cfnode.referrals:
|
|
Packit |
01965a |
UIReferralNode(self, r)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_create(self, name):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Creates a new referral.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{delete}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
r = nvme.Referral(self.parent.cfnode, name, mode='create')
|
|
Packit |
01965a |
UIReferralNode(self, r)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_delete(self, name):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Deletes the referral with the specified I{name}.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{create}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
r = nvme.Referral(self.parent.cfnode, name, mode='lookup')
|
|
Packit |
01965a |
r.delete()
|
|
Packit |
01965a |
self.refresh()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UIReferralNode(UINode):
|
|
Packit |
01965a |
ui_desc_addr = {
|
|
Packit |
01965a |
'adrfam': ('string', 'Address Family (e.g. ipv4 or fc)'),
|
|
Packit |
01965a |
'treq': ('string', 'Transport Security Requirements'),
|
|
Packit |
01965a |
'traddr': ('string', 'Transport Address (e.g. IP Address or FC wwnn:wwpn)'),
|
|
Packit |
01965a |
'trsvcid': ('string', 'Transport Service ID (e.g. IP Port)'),
|
|
Packit |
01965a |
'trtype': ('string', 'Transport Type (e.g. rdma or loop or fc)'),
|
|
Packit |
01965a |
'portid': ('number', 'Port identifier'),
|
|
Packit |
01965a |
}
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def __init__(self, parent, cfnode):
|
|
Packit |
01965a |
UINode.__init__(self, cfnode.name, parent, cfnode)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def status(self):
|
|
Packit |
01965a |
if self.cfnode.get_enable():
|
|
Packit |
01965a |
return "enabled"
|
|
Packit |
01965a |
return "disabled"
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_enable(self):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Enables the current Referral.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{disable}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
if self.cfnode.get_enable():
|
|
Packit |
01965a |
self.shell.log.info("The Referral is already enabled.")
|
|
Packit |
01965a |
else:
|
|
Packit |
01965a |
try:
|
|
Packit |
01965a |
self.cfnode.set_enable(1)
|
|
Packit |
01965a |
self.shell.log.info("The Referral has been enabled.")
|
|
Packit |
01965a |
except Exception as e:
|
|
Packit |
01965a |
raise configshell.ExecutionError(
|
|
Packit |
01965a |
"The Referral could not be enabled.")
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_disable(self):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Disables the current Referral.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{enable}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
if not self.cfnode.get_enable():
|
|
Packit |
01965a |
self.shell.log.info("The Referral is already disabled.")
|
|
Packit |
01965a |
else:
|
|
Packit |
01965a |
try:
|
|
Packit |
01965a |
self.cfnode.set_enable(0)
|
|
Packit |
01965a |
self.shell.log.info("The Referral has been disabled.")
|
|
Packit |
01965a |
except Exception as e:
|
|
Packit |
01965a |
raise configshell.ExecutionError(
|
|
Packit |
01965a |
"The Referral could not be disabled.")
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UIHostsNode(UINode):
|
|
Packit |
01965a |
def __init__(self, parent):
|
|
Packit |
01965a |
UINode.__init__(self, 'hosts', parent)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def refresh(self):
|
|
Packit |
01965a |
self._children = set([])
|
|
Packit |
01965a |
for host in self.parent.cfnode.hosts:
|
|
Packit |
01965a |
UIHostNode(self, host)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_create(self, nqn):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Creates a new NVMe host.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{delete}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
host = nvme.Host(nqn, mode='create')
|
|
Packit |
01965a |
UIHostNode(self, host)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ui_command_delete(self, nqn):
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
Recursively deletes the NVMe Host with the specified I{nqn}, and all
|
|
Packit |
01965a |
objects hanging under it.
|
|
Packit |
01965a |
|
|
Packit |
01965a |
SEE ALSO
|
|
Packit |
01965a |
========
|
|
Packit |
01965a |
B{create}
|
|
Packit |
01965a |
'''
|
|
Packit |
01965a |
host = nvme.Host(nqn, mode='lookup')
|
|
Packit |
01965a |
host.delete()
|
|
Packit |
01965a |
self.refresh()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
class UIHostNode(UINode):
|
|
Packit |
01965a |
def __init__(self, parent, cfnode):
|
|
Packit |
01965a |
UINode.__init__(self, cfnode.nqn, parent, cfnode)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def usage():
|
|
Packit |
01965a |
print("syntax: %s save [file_to_save_to]" % sys.argv[0])
|
|
Packit |
01965a |
print(" %s restore [file_to_restore_from]" % sys.argv[0])
|
|
Packit |
01965a |
print(" %s clear" % sys.argv[0])
|
|
Packit |
01965a |
print(" %s ls" % sys.argv[0])
|
|
Packit |
01965a |
sys.exit(-1)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def save(to_file):
|
|
Packit |
01965a |
nvme.Root().save_to_file(to_file)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def restore(from_file):
|
|
Packit |
01965a |
try:
|
|
Packit |
01965a |
errors = nvme.Root().restore_from_file(from_file)
|
|
Packit |
01965a |
except IOError:
|
|
Packit |
01965a |
# Not an error if the restore file is not present
|
|
Packit |
01965a |
print("No saved config file at %s, ok, exiting" % from_file)
|
|
Packit |
01965a |
sys.exit(0)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
for error in errors:
|
|
Packit |
01965a |
print(error)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def clear(unused):
|
|
Packit |
01965a |
nvme.Root().clear_existing()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def ls(unused):
|
|
Packit |
01965a |
shell = configshell.shell.ConfigShell('~/.nvmetcli')
|
|
Packit |
01965a |
UIRootNode(shell)
|
|
Packit |
01965a |
shell.run_cmdline("ls")
|
|
Packit |
01965a |
sys.exit(0)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
funcs = dict(save=save, restore=restore, clear=clear, ls=ls)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
|
|
Packit |
01965a |
def main():
|
|
Packit |
01965a |
if os.geteuid() != 0:
|
|
Packit |
01965a |
print("%s: must run as root." % sys.argv[0], file=sys.stderr)
|
|
Packit |
01965a |
sys.exit(-1)
|
|
Packit |
01965a |
|
|
Packit |
01965a |
if len(sys.argv) > 3:
|
|
Packit |
01965a |
usage()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
if len(sys.argv) == 2 or len(sys.argv) == 3:
|
|
Packit |
01965a |
if sys.argv[1] == "--help":
|
|
Packit |
01965a |
usage()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
if sys.argv[1] not in funcs.keys():
|
|
Packit |
01965a |
usage()
|
|
Packit |
01965a |
|
|
Packit |
01965a |
if len(sys.argv) == 3:
|
|
Packit |
01965a |
savefile = sys.argv[2]
|
|
Packit |
01965a |
else:
|
|
Packit |
01965a |
savefile = None
|
|
Packit |
01965a |
|
|
Packit |
01965a |
funcs[sys.argv[1]](savefile)
|
|
Packit |
01965a |
return
|
|
Packit |
01965a |
|
|
Packit |
01965a |
try:
|
|
Packit |
01965a |
shell = configshell.shell.ConfigShell('~/.nvmetcli')
|
|
Packit |
01965a |
UIRootNode(shell)
|
|
Packit |
01965a |
except Exception as msg:
|
|
Packit |
01965a |
shell.log.error(str(msg))
|
|
Packit |
01965a |
return
|
|
Packit |
01965a |
|
|
Packit |
01965a |
while not shell._exit:
|
|
Packit |
01965a |
try:
|
|
Packit |
01965a |
shell.run_interactive()
|
|
Packit |
01965a |
except Exception as msg:
|
|
Packit |
01965a |
shell.log.error(str(msg))
|
|
Packit |
01965a |
|
|
Packit |
01965a |
if __name__ == "__main__":
|
|
Packit |
01965a |
main()
|