示例#1
0
    def setUpClass(cls):
        udiskstestcase.UdisksTestCase.setUpClass()
        if not shutil.which("nvme"):
            udiskstestcase.UdisksTestCase.tearDownClass()
            raise unittest.SkipTest(
                "nvme executable (nvme-cli package) not found in $PATH, skipping."
            )
        if not shutil.which("nvmetcli"):
            udiskstestcase.UdisksTestCase.tearDownClass()
            raise unittest.SkipTest(
                "nvmetcli executable not found in $PATH, skipping.")
        ret, out = udiskstestcase.run_command("modprobe nvme-fabrics")
        if ret != 0:
            raise unittest.SkipTest(
                "nvme-fabrics kernel module unavailable, skipping.")

        manager = cls.get_interface("/Manager", ".Manager")
        cls.loop_devs = []

        for i in range(cls.NUM_NS):
            with tempfile.NamedTemporaryFile(prefix="udisks_test",
                                             delete=True,
                                             mode='w+b') as temp:
                temp.truncate(cls.NS_SIZE)
                loop_dev_obj_path = manager.LoopSetup(temp.fileno(),
                                                      cls.no_options)
                path, loop_dev = loop_dev_obj_path.rsplit("/", 1)
                cls.loop_devs += ["/dev/%s" % loop_dev]

        cls.hostnqn = get_nvme_hostnqn()
        setup_nvme_target(cls.loop_devs, cls.SUBNQN)
示例#2
0
 def tearDownClass(cls):
     ret, out = udiskstestcase.run_command("nvmetcli clear")
     if ret != 0:
         raise RuntimeError("Error clearing the NVMe target: %s" % out)
     # detach loop devices
     for i in cls.loop_devs:
         cls.run_command("losetup --detach %s" % i)
     udiskstestcase.UdisksTestCase.tearDownClass()
示例#3
0
def find_nvme_ns_devs_for_subnqn(subnqn):
    """
    Find NVMe namespace block devices for the specified subsystem nqn

    :param str subnqn: subsystem nqn
    """
    def _check_namespaces(node, ns_dev_paths):
        for ns in node['Namespaces']:
            path = os.path.join('/dev/', ns['NameSpace'])
            try:
                st = os.lstat(path)
                if stat.S_ISBLK(st.st_mode):
                    ns_dev_paths += [path]
            except:
                pass

    def _check_subsys(subsys, ns_dev_paths):
        if subsys['SubsystemNQN'] == subnqn:
            if 'Namespaces' in subsys:
                _check_namespaces(subsys, ns_dev_paths)
            # kernel 4.18
            if 'Controllers' in subsys:
                for ctrl in subsys['Controllers']:
                    if 'Namespaces' in ctrl:
                        _check_namespaces(ctrl, ns_dev_paths)

    ret, out = udiskstestcase.run_command(
        "nvme list --output-format=json --verbose")
    if ret != 0:
        raise RuntimeError("Error getting NVMe list: %s" % out)

    decoder = json.JSONDecoder()
    decoded = decoder.decode(out)
    if not decoded or 'Devices' not in decoded:
        return []

    ns_dev_paths = []
    for dev in decoded['Devices']:
        # nvme-cli 2.x
        if 'Subsystems' in dev:
            for subsys in dev['Subsystems']:
                _check_subsys(subsys, ns_dev_paths)
        # nvme-cli 1.x
        if 'SubsystemNQN' in dev:
            _check_subsys(dev, ns_dev_paths)

    return ns_dev_paths
示例#4
0
def get_nvme_hostnqn():
    """
    Retrieves NVMe host NQN string from /etc/nvme/hostnqn or uses nvme-cli to generate
    new one (stable, typically generated from machine DMI data) when not available.
    """

    hostnqn = None
    try:
        hostnqn = read_file('/etc/nvme/hostnqn')
    except:
        pass

    if hostnqn is None or len(hostnqn.strip()) < 1:
        ret, hostnqn = udiskstestcase.run_command('nvme gen-hostnqn')
        if ret != 0:
            raise RuntimeError("Cannot get host NQN: '%s %s'" % (hostnqn, err))

    return hostnqn.strip()
示例#5
0
def find_nvme_ctrl_devs_for_subnqn(subnqn):
    """
    Find NVMe controller devices for the specified subsystem nqn

    :param str subnqn: subsystem nqn
    """
    def _check_subsys(subsys, dev_paths):
        if subsys['SubsystemNQN'] == subnqn:
            for ctrl in subsys['Controllers']:
                path = os.path.join('/dev/', ctrl['Controller'])
                try:
                    st = os.lstat(path)
                    # nvme controller node is a character device
                    if stat.S_ISCHR(st.st_mode):
                        dev_paths += [path]
                except:
                    pass

    ret, out = udiskstestcase.run_command(
        "nvme list --output-format=json --verbose")
    if ret != 0:
        raise RuntimeError("Error getting NVMe list: %s" % out)

    decoder = json.JSONDecoder()
    decoded = decoder.decode(out)
    if not decoded or 'Devices' not in decoded:
        return []

    dev_paths = []
    for dev in decoded['Devices']:
        # nvme-cli 2.x
        if 'Subsystems' in dev:
            for subsys in dev['Subsystems']:
                _check_subsys(subsys, dev_paths)
        # nvme-cli 1.x
        if 'SubsystemNQN' in dev:
            _check_subsys(dev, dev_paths)

    return dev_paths
示例#6
0
def setup_nvme_target(dev_paths, subnqn):
    """
    Sets up a new NVMe target loop device (using nvmetcli) on top of the
    :param:`dev_paths` backing block devices.

    :param set dev_paths: set of backing block device paths
    :param str subnqn: Subsystem NQN
    """

    # modprobe required nvme target modules
    for module in ['nvmet', 'nvme-loop']:
        ret, out = udiskstestcase.run_command("modprobe %s" % module)
        if ret != 0:
            raise RuntimeError("Cannot load required NVMe target modules: %s" %
                               out)

    # create a JSON file for nvmetcli
    with tempfile.NamedTemporaryFile(mode='wt', delete=False) as tmp:
        tcli_json_file = tmp.name
        namespaces = ",".join([
            """
        {{
          "device": {{
            "nguid": "{nguid}",
            "path": "{path}"
          }},
          "enable": 1,
          "nsid": {nsid}
        }}
        """.format(nguid=uuid.uuid4(), path=dev_path, nsid=i)
            for i, dev_path in enumerate(dev_paths, start=1)
        ])

        json = """
{
  "ports": [
    {
      "addr": {
        "adrfam": "",
        "traddr": "",
        "treq": "not specified",
        "trsvcid": "",
        "trtype": "loop"
      },
      "portid": 1,
      "referrals": [],
      "subsystems": [
        "%s"
      ]
    }
  ],
  "subsystems": [
    {
      "attr": {
        "allow_any_host": "1"
      },
      "namespaces": [
%s
      ],
      "nqn": "%s"
    }
  ]
}
"""
        tmp.write(json % (subnqn, namespaces, subnqn))

    ret, out = udiskstestcase.run_command("nvmetcli restore %s" %
                                          tcli_json_file)
    os.unlink(tcli_json_file)
    if ret != 0:
        raise RuntimeError("Error setting up the NVMe target: %s" % out)