]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
cephadm: Add rescan_disks subcommand
authorPaul Cuzner <pcuzner@redhat.com>
Mon, 30 May 2022 01:52:57 +0000 (13:52 +1200)
committerAdam King <adking@redhat.com>
Sun, 31 Jul 2022 18:16:45 +0000 (14:16 -0400)
Add a new subcommand to probe each HBA to
force discovery of decies not automatically detected
by the kernel.

Signed-off-by: Paul Cuzner <pcuzner@redhat.com>
(cherry picked from commit 6584c49bdf254e8750d23ed529478e6a9289e12f)

src/cephadm/cephadm

index ecdc6fc5d48b89e64428749c052926217cd4c527..b6d7d2202e05b50fb814b3b3623c72f867862400 100755 (executable)
@@ -107,9 +107,26 @@ You can invoke cephadm in two ways:
 """
 cached_stdin = None
 
+
 ##################################
 
 
+async def run_func(func: Callable, cmd: str) -> subprocess.CompletedProcess:
+    logger.debug(f'running function {func.__name__}, with parms: {cmd}')
+    response = func(cmd)
+    return response
+
+
+async def concurrent_tasks(func: Callable, cmd_list: List[str]) -> List[Any]:
+    tasks = []
+    for cmd in cmd_list:
+        tasks.append(run_func(func, cmd))
+
+    data = await asyncio.gather(*tasks)
+
+    return data
+
+
 class EndPoint:
     """EndPoint representing an ip:port format"""
 
@@ -7852,6 +7869,50 @@ def command_install(ctx: CephadmContext) -> None:
     pkg = create_packager(ctx)
     pkg.install(ctx.packages)
 
+
+def command_rescan_disks(ctx: CephadmContext) -> str:
+
+    def probe_hba(scan_path: str) -> None:
+        """Tell the adapter to rescan"""
+        with open(scan_path, 'w') as f:
+            f.write('- - -')
+
+    cmd = ctx.func.__name__.replace('command_', '')
+    logger.info(f'{cmd}: starting')
+    start = time.time()
+
+    all_scan_files = glob('/sys/class/scsi_host/*/scan')
+    scan_files = []
+    skipped = []
+    for scan_path in all_scan_files:
+        adapter_name = os.path.basename(os.path.dirname(scan_path))
+        proc_name = read_file([os.path.join(os.path.dirname(scan_path), 'proc_name')])
+        if proc_name in ['unknown', 'usb-storage']:
+            skipped.append(os.path.basename(scan_path))
+            logger.info(f'{cmd}: rescan skipping incompatible host adapter {adapter_name} : {proc_name}')
+            continue
+
+        scan_files.append(scan_path)
+
+    if not scan_files:
+        logger.info(f'{cmd}: no compatible HBAs found')
+        return 'Ok. No compatible HBAs found'
+
+    responses = async_run(concurrent_tasks(probe_hba, scan_files))
+    failures = [r for r in responses if r]
+
+    logger.info(f'{cmd}: Complete. {len(scan_files)} adapters rescanned, {len(failures)} failures, {len(skipped)} skipped')
+
+    elapsed = time.time() - start
+    if failures:
+        plural = 's' if len(failures) > 1 else ''
+        if len(failures) == len(scan_files):
+            return f'Failed. All {len(scan_files)} rescan requests failed'
+        else:
+            return f'Partial. {len(scan_files) - len(failures)} successful, {len(failures)} failure{plural} against: {", ".join(failures)}'
+
+    return f'Ok. {len(all_scan_files)} adapters detected: {len(scan_files)} rescanned, {len(skipped)} skipped, {len(failures)} failed ({elapsed:.2f}s)'
+
 ##################################
 
 
@@ -9194,6 +9255,10 @@ def _get_parser():
         '--daemon-id',
         help='daemon id for agent')
 
+    parser_agent = subparsers.add_parser(
+        'disk-rescan', help='rescan all HBAs to detect new/removed devices')
+    parser_agent.set_defaults(func=command_rescan_disks)
+
     return parser