summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/services/tcmu_service.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/pybind/mgr/dashboard/services/tcmu_service.py
parentInitial commit. (diff)
downloadceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz
ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/pybind/mgr/dashboard/services/tcmu_service.py')
-rw-r--r--src/pybind/mgr/dashboard/services/tcmu_service.py113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/services/tcmu_service.py b/src/pybind/mgr/dashboard/services/tcmu_service.py
new file mode 100644
index 000000000..a81b6e8f2
--- /dev/null
+++ b/src/pybind/mgr/dashboard/services/tcmu_service.py
@@ -0,0 +1,113 @@
+from mgr_util import get_most_recent_rate
+
+from dashboard.services.ceph_service import CephService
+
+from .. import mgr
+
+try:
+ from typing import Dict
+except ImportError:
+ pass # Just for type checking
+
+
+SERVICE_TYPE = 'tcmu-runner'
+
+
+class TcmuService(object):
+ # pylint: disable=too-many-nested-blocks
+ # pylint: disable=too-many-branches
+ @staticmethod
+ def get_iscsi_info():
+ daemons = {} # type: Dict[str, dict]
+ images = {} # type: Dict[str, dict]
+ daemon = None
+ for service in CephService.get_service_list(SERVICE_TYPE):
+ metadata = service['metadata']
+ if metadata is None:
+ continue
+ status = service['status']
+ hostname = service['hostname']
+
+ daemon = daemons.get(hostname, None)
+ if daemon is None:
+ daemon = {
+ 'server_hostname': hostname,
+ 'version': metadata['ceph_version'],
+ 'optimized_paths': 0,
+ 'non_optimized_paths': 0
+ }
+ daemons[hostname] = daemon
+
+ service_id = service['id']
+ device_id = service_id.split(':')[-1]
+ image = images.get(device_id)
+ if image is None:
+ image = {
+ 'device_id': device_id,
+ 'pool_name': metadata['pool_name'],
+ 'name': metadata['image_name'],
+ 'id': metadata.get('image_id', None),
+ 'optimized_paths': [],
+ 'non_optimized_paths': []
+ }
+ images[device_id] = image
+
+ if status.get('lock_owner', 'false') == 'true':
+ daemon['optimized_paths'] += 1
+ image['optimized_paths'].append(hostname)
+
+ perf_key_prefix = "librbd-{id}-{pool}-{name}.".format(
+ id=metadata.get('image_id', ''),
+ pool=metadata['pool_name'],
+ name=metadata['image_name'])
+ perf_key = "{}lock_acquired_time".format(perf_key_prefix)
+ perf_value = mgr.get_counter('tcmu-runner',
+ service_id,
+ perf_key)[perf_key]
+ if perf_value:
+ lock_acquired_time = perf_value[-1][1] / 1000000000
+ else:
+ lock_acquired_time = 0
+ if lock_acquired_time > image.get('optimized_since', 0):
+ image['optimized_daemon'] = hostname
+ image['optimized_since'] = lock_acquired_time
+ image['stats'] = {}
+ image['stats_history'] = {}
+ for s in ['rd', 'wr', 'rd_bytes', 'wr_bytes']:
+ perf_key = "{}{}".format(perf_key_prefix, s)
+ rates = CephService.get_rates('tcmu-runner', service_id, perf_key)
+ image['stats'][s] = get_most_recent_rate(rates)
+ image['stats_history'][s] = rates
+ else:
+ daemon['non_optimized_paths'] += 1
+ image['non_optimized_paths'].append(hostname)
+
+ # clear up races w/ tcmu-runner clients that haven't detected
+ # loss of optimized path
+ TcmuService.remove_undetected_clients(images, daemons, daemon)
+
+ return {
+ 'daemons': sorted(daemons.values(),
+ key=lambda d: d['server_hostname']),
+ 'images': sorted(images.values(), key=lambda i: ['id']),
+ }
+
+ @staticmethod
+ def get_image_info(pool_name, image_name, get_iscsi_info):
+ for image in get_iscsi_info['images']:
+ if image['pool_name'] == pool_name and image['name'] == image_name:
+ return image
+ return None
+
+ @staticmethod
+ def remove_undetected_clients(images, daemons, daemon):
+ for image in images.values():
+ optimized_daemon = image.get('optimized_daemon', None)
+ if optimized_daemon:
+ for daemon_name in image['optimized_paths']:
+ if daemon_name != optimized_daemon:
+ daemon = daemons[daemon_name]
+ daemon['optimized_paths'] -= 1
+ daemon['non_optimized_paths'] += 1
+ image['non_optimized_paths'].append(daemon_name)
+ image['optimized_paths'] = [optimized_daemon]