Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mgr: dashboard code cleanup #15577

Merged
merged 4 commits into from Jun 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 39 additions & 7 deletions src/pybind/mgr/dashboard/module.py
Expand Up @@ -31,6 +31,7 @@ def global_instance():
from types import OsdMap, NotFound, Config, FsMap, MonMap, \
PgSummary, Health, MonStatus

import rados
from rbd_ls import RbdLs
from cephfs_clients import CephFSClients

Expand Down Expand Up @@ -63,6 +64,9 @@ def __init__(self, *args, **kwargs):

self.log_buffer = collections.deque(maxlen=LOG_BUFFER_SIZE)

# Keep a librados instance for those that need it.
self._rados = None

# Stateful instances of RbdLs, hold cached results. Key to dict
# is pool name.
self.rbd_ls = {}
Expand All @@ -75,6 +79,28 @@ def __init__(self, *args, **kwargs):
self.pool_stats = defaultdict(lambda: defaultdict(
lambda: collections.deque(maxlen=10)))

@property
def rados(self):
"""
A librados instance to be shared by any classes within
this mgr module that want one.
"""
if self._rados:
return self._rados

from mgr_module import ceph_state
ctx_capsule = ceph_state.get_context()
self._rados = rados.Rados(context=ctx_capsule)
self._rados.connect()

return self._rados

def get_localized_config(self, key):
r = self.get_config(self.get_mgr_id() + '/' + key)
if r is None:
r = self.get_config(key)
return r

def update_pool_stats(self):
df = global_instance().get("df")
pool_stats = dict([(p['id'], p['stats']) for p in df['pools']])
Expand Down Expand Up @@ -103,26 +129,26 @@ def get_sync_object(self, object_type, path=None):
data['crush'] = self.get("osd_map_crush")
data['crush_map_text'] = self.get("osd_map_crush_map_text")
data['osd_metadata'] = self.get("osd_metadata")
obj = OsdMap(data['epoch'], data)
obj = OsdMap(data)
elif object_type == Config:
data = self.get("config")
obj = Config(0, data)
obj = Config( data)
elif object_type == MonMap:
data = self.get("mon_map")
obj = MonMap(data['epoch'], data)
obj = MonMap(data)
elif object_type == FsMap:
data = self.get("fs_map")
obj = FsMap(data['epoch'], data)
obj = FsMap(data)
elif object_type == PgSummary:
data = self.get("pg_summary")
self.log.debug("JSON: {0}".format(data))
obj = PgSummary(0, data)
obj = PgSummary(data)
elif object_type == Health:
data = self.get("health")
obj = Health(0, json.loads(data['json']))
obj = Health(json.loads(data['json']))
elif object_type == MonStatus:
data = self.get("mon_status")
obj = MonStatus(0, json.loads(data['json']))
obj = MonStatus(json.loads(data['json']))
else:
raise NotImplementedError(object_type)

Expand All @@ -145,6 +171,11 @@ def shutdown(self):
cherrypy.engine.exit()
log.info("Stopped server")

log.info("Stopping librados...")
if self._rados:
self._rados.shutdown()
log.info("Stopped librados.")

def get_latest(self, daemon_type, daemon_name, stat):
data = self.get_counter(daemon_type, daemon_name, stat)[stat]
if data:
Expand Down Expand Up @@ -546,6 +577,7 @@ def servers(self):
)

def _servers(self):
servers = global_instance().list_servers()
return {
'servers': global_instance().list_servers()
}
Expand Down
15 changes: 7 additions & 8 deletions src/pybind/mgr/dashboard/remote_view_cache.py
Expand Up @@ -22,13 +22,12 @@ def run(self):
self._view.value = None
self._view.value_when = None
self._view.getter_thread = None
self.event.set()

with self._view.lock:
self._view.latency = t1 - t0
self._view.value = val
self._view.value_when = datetime.datetime.now()
self._view.getter_thread = None
else:
with self._view.lock:
self._view.latency = t1 - t0
self._view.value = val
self._view.value_when = datetime.datetime.now()
self._view.getter_thread = None

self.event.set()

Expand Down Expand Up @@ -133,4 +132,4 @@ def _init(self):
pass

def _get(self):
raise NotImplementedError()
raise NotImplementedError()
15 changes: 11 additions & 4 deletions src/pybind/mgr/dashboard/servers.html
Expand Up @@ -24,9 +24,16 @@
};

rivets.formatters.short_version = function(version) {
// Turn "ceph version 1.2.3-g9asdasd (as98d7a0s8d7)"
// into "1.2.3-g9asdasd"
return /ceph version (.+) \(.+\)$/.exec(version)[1];
// Expect "ceph version 1.2.3-g9asdasd (as98d7a0s8d7)"
var result = /ceph version\s+([^ ]+)\s+\(.+\)/.exec(version);
if (result) {
// Return the "1.2.3-g9asdasd" part
return result[1];
} else {
// Unexpected format, pass it through
return version;
}
return
};

rivets.bind($("#content"), content_data);
Expand Down Expand Up @@ -74,4 +81,4 @@ <h1>
</div>
</section>

{% endblock %}
{% endblock %}
58 changes: 15 additions & 43 deletions src/pybind/mgr/dashboard/types.py
Expand Up @@ -33,47 +33,19 @@ def wrapper(*args):
return wrapper


class SyncObject(object):
"""
An object from a Ceph cluster that we are maintaining
a copy of on the Calamari server.

We wrap these JSON-serializable objects in a python object to:

- Decorate them with things like id-to-entry dicts
- Have a generic way of seeing the version of an object
OSD_FLAGS = ('pause', 'noup', 'nodown', 'noout', 'noin', 'nobackfill',
'norecover', 'noscrub', 'nodeep-scrub')

"""
def __init__(self, version, data):
self.version = version
class DataWrapper(object):
def __init__(self, data):
self.data = data

@classmethod
def cmp(cls, a, b):
"""
Slight bastardization of cmp. Takes two versions,
and returns a cmp-like value, except that if versions
are not sortable we only return 0 or 1.
"""
# Version is something unique per version (like a hash)
return 1 if a != b else 0


class VersionedSyncObject(SyncObject):
@classmethod
def cmp(cls, a, b):
# Version is something numeric like an epoch
return cmp(a, b)


OSD_FLAGS = ('pause', 'noup', 'nodown', 'noout', 'noin', 'nobackfill', 'norecover', 'noscrub', 'nodeep-scrub')


class OsdMap(VersionedSyncObject):
class OsdMap(DataWrapper):
str = OSD_MAP

def __init__(self, version, data):
super(OsdMap, self).__init__(version, data)
def __init__(self, data):
super(OsdMap, self).__init__(data)
if data is not None:
self.osds_by_id = dict([(o['osd'], o) for o in data['osds']])
self.pools_by_id = dict([(p['pool'], p) for p in data['pools']])
Expand Down Expand Up @@ -204,37 +176,37 @@ def osd_pools(self):
return osds


class FsMap(VersionedSyncObject):
class FsMap(DataWrapper):
str = 'fs_map'


class MonMap(VersionedSyncObject):
class MonMap(DataWrapper):
str = 'mon_map'


class MonStatus(VersionedSyncObject):
class MonStatus(DataWrapper):
str = 'mon_status'

def __init__(self, version, data):
super(MonStatus, self).__init__(version, data)
def __init__(self, data):
super(MonStatus, self).__init__(data)
if data is not None:
self.mons_by_rank = dict([(m['rank'], m) for m in data['monmap']['mons']])
else:
self.mons_by_rank = {}


class PgSummary(SyncObject):
class PgSummary(DataWrapper):
"""
A summary of the state of PGs in the cluster, reported by pool and by OSD.
"""
str = 'pg_summary'


class Health(SyncObject):
class Health(DataWrapper):
str = 'health'


class Config(SyncObject):
class Config(DataWrapper):
str = 'config'


Expand Down