Loading ccnode/host/__init__.py +103 −0 Original line number Diff line number Diff line import inspect import logging from subprocess import Popen, PIPE, STDOUT from sjrpc.utils import pure from ccnode.node import DefaultHandler from ccnode.tags import Tag, DynamicTags from ccnode.host import tags logger = logging.getLogger(__name__) class Handler(DefaultHandler): """Handler for host role.""" def __init__(self, *args, **kwargs): DefaultHandler.__init__(self, *args, **kwargs) # add host tags to self.tags dict [ 'cpu', 'cpuuse', 'arch', 'chaserial', 'cpufreq', 'disk', 'hmodel', 'hserial', 'hvendor', 'hbios', 'load', 'mem', 'memfree', 'memused', 'os', 'platform', 'sto', 'uname', 'uptime', ] logger.debug(u'Begin introspection') for n, m in inspect.getmembers(tags): # (name, member) # only keep strings or functions as tags if getattr(m, '__module__', None) != 'ccnode.host.tags' or ( n.startswith('_')): continue elif isinstance(m, (str, unicode)): # if string, it means it is constant, then ttl = -1 ttl = -1 elif inspect.isfunction(m): # if function take function ttl argument or set -1 by default ttl = getattr(m, 'ttl', -1) elif isinstance(m, DynamicTags): logger.debug('plop') for t in m.iter_tags(): self.tags[t.name] = t logger.debug('Introspected %s with ttl %s.' % (t.name, t.ttl)) continue else: continue logger.debug('Introspected %s with ttl %s.' % (n, ttl)) # finally add the tag self.tags[n] = Tag(n, m, ttl) logger.debug(u'End introspection') @pure def execute_command(self, command): """Execute an arbitrary shell command on the host. :param string command: shell command to run """ # return stdout and stderr mixed in return Popen(command, shell=True, bufsize=-1, stdin=PIPE, stdout=PIPE, stderr=STDOUT).communicate()[0] or None @pure def node_shutdown(self, reboot=True, gracefull=True): """Halt/Reboot the node.""" args = ['/sbin/shutdown'] if reboot: args.append('-r') if gracefull: logger.info(u'Going to reboot the host...') args.append('-f') else: logger.info(u'Going to force the reboot of the host...') args.append('-n') else: # halt args.append('-h -P') if not gracefull: logger.info(u'Going to halt the host...') args.append('-n') else: logger.info(u'Going to force the halt of the host...') args.append('0') return self.execute_command(' '.join(args)) ccnode/host/handler.pydeleted 100644 → 0 +0 −0 Empty file deleted. ccnode/host/tags.py 0 → 100644 +170 −0 Original line number Diff line number Diff line """This module acts as a little framework for defining tags in a simple way. Just define a string or a function and it will be introspected and used as a tag value. """ import re import os as os_ import platform as platform_ from multiprocessing import cpu_count from socket import gethostname, gethostbyaddr import psutil from ccnode.tags import Tag, DynamicTags def h(): """Hostname tag.""" hn = gethostname() return gethostbyaddr(hn)[0] or hn h.ttl = 3600 * 24 # one day # CPU related tags def arch(): """Hardware CPU architecture.""" return { u'i386': u'x86', u'i486': u'x86', u'i586': u'x86', u'i686': u'x86', u'x86_64': u'x64', u'': None, }[platform_.machine()] def cpu(): """Number of CPU (core) on the host.""" try: return unicode(cpu_count()) except NotImplementedError: return None def cpuuse(): """CPU usage in percentage.""" return u'%.1f' % psutil.cpu_percent() cpuuse.ttl = 5 # memory related tags def mem(): """Total physical memory available on system.""" return unicode(psutil.avail_phymem() + psutil.used_phymem()) mem.ttl = -1 # FIXME validate ttl def memfree(): """Available physical memory on system.""" return unicode(psutil.avail_phymem()) memfree.ttl = 60 def memused(): """Used physical memory on system.""" return unicode(psutil.used_phymem()) memused.ttl = 60 # disks related tags def disk(): """List of disk devices on the host.""" disk_pattern = re.compile(r'[sh]d[a-z]+') return u' '.join(d for d in os_.listdir( '/sys/block/') if disk_pattern.match(d)) def _disk_tag_value(disk_name): def size(): s = open(os_.path.join('/sys/block', disk_name, 'size')).read().strip() try: s = int(s) if s > 0: return s * 512 else: return None except ValueError: return None return size class DynamicDisks(DynamicTags): def __init__(self): DynamicTags.__init__(self) for d in disk().split(): self.tags.append(Tag(u'disk%s_size' % d, _disk_tag_value(d), 3600)) disks_size = DynamicDisks() # other hardware related tags def chaserial(): """Blade chassis serial number.""" return open('/sys/class/dmi/id/chassis_serial').read().strip() or None def chaasset(): """Blade chassis asset tag.""" return open('/sys/class/dmi/id/chassis_asset_tag').read().strip() or None def hmodel(): """Host hardware model.""" return open('/sys/class/dmi/id/product_name').read().strip() or None def hserial(): """Host hardware serial number.""" return open('/sys/class/dmi/id/product_serial').read().strip() or None def hvendor(): """Host hardware vendor.""" return open('/sys/class/dmi/id/sys_vendor').read().strip() or None def hbios(): """Host BIOS version.""" return u'%s (%s)' % ( open('/sys/class/dmi/id/bios_version').read().strip() or None, open('/sys/class/dmi/id/bios_date').read().strip() or None, ) # Operating system related tags def os(): """Operating system (linux/windows).""" return unicode(platform_.system().lower()) def platform(): """Python platform.platform() info.""" return unicode(platform_.platform()) def uname(): """As uname command (see python os.uname).""" return u' '.join(os_.uname()) or None def uptime(): """Uptime of the system in seconds.""" return open('/proc/uptime').read().split()[0].split(u'.')[0] or None uptime.ttl = 5 def load(): """Average of the number of processes in the run queue over the last 1, 5 and 15 minutes.""" load_ = None try: load_ = u' '.join(unicode(l) for l in os_.getloadavg()) except OSError: pass return load_ load.ttl = 5 ccnode/node.py +20 −8 Original line number Diff line number Diff line Loading @@ -27,7 +27,10 @@ class DefaultHandler(RpcHandler): :param iterable tags: list of tags to return :param iterable noresolve_tags: list of tags to not return """ logger.debug('Tags: %s, %s' % (unicode(tags), unicode(noresolve_tags))) logger.debug('Tags request: %s, %s' % ( unicode(tags), unicode(noresolve_tags), )) tags = set(tags) - set(noresolve_tags) if tags is not None else None Loading @@ -36,6 +39,8 @@ class DefaultHandler(RpcHandler): else: tags = tags & set(self.tags.iterkeys()) profile = time.time() try: result = dict(( t, # tag name dict( Loading @@ -43,6 +48,10 @@ class DefaultHandler(RpcHandler): ttl=self.tags[t].ttl, ), ) for t in tags) except Exception: logger.exception(u'SHould not happend, result.') logger.debug(u'Profiling: %f seconds.' % (time.time() - profile)) logger.debug(u'Returning: %s' % unicode(result)) return result Loading Loading @@ -98,6 +107,9 @@ class Node(Thread): # set handler according to which role was returned by the cc-server if role == u'host': logger.debug(u'Role host affected.') from ccnode.host import Handler as HostHandler # FIXME bad API self.manager._connection.set_handler(HostHandler()) self.role = u'host' elif role == u'hv': logger.debug(u'Role hypervisor affected.') Loading ccnode/tags.py +20 −1 Original line number Diff line number Diff line import logging from inspect import isfunction logger = logging.getLogger(__name__) class Tag(object): """Class that abstract tags.""" def __init__(self, name, valuable, ttl): Loading @@ -17,6 +21,21 @@ class Tag(object): def value(self): """Returns tag value.""" if isfunction(self._value): try: return self._value() except Exception: logger.exception(u'Calculating tag %s failed:' % self.name) return None return self._value class DynamicTags(object): """Set tags dynamicaly.""" def __init__(self): """Here define the tags.""" self.tags = [] def iter_tags(self): for t in self.tags: yield t Loading
ccnode/host/__init__.py +103 −0 Original line number Diff line number Diff line import inspect import logging from subprocess import Popen, PIPE, STDOUT from sjrpc.utils import pure from ccnode.node import DefaultHandler from ccnode.tags import Tag, DynamicTags from ccnode.host import tags logger = logging.getLogger(__name__) class Handler(DefaultHandler): """Handler for host role.""" def __init__(self, *args, **kwargs): DefaultHandler.__init__(self, *args, **kwargs) # add host tags to self.tags dict [ 'cpu', 'cpuuse', 'arch', 'chaserial', 'cpufreq', 'disk', 'hmodel', 'hserial', 'hvendor', 'hbios', 'load', 'mem', 'memfree', 'memused', 'os', 'platform', 'sto', 'uname', 'uptime', ] logger.debug(u'Begin introspection') for n, m in inspect.getmembers(tags): # (name, member) # only keep strings or functions as tags if getattr(m, '__module__', None) != 'ccnode.host.tags' or ( n.startswith('_')): continue elif isinstance(m, (str, unicode)): # if string, it means it is constant, then ttl = -1 ttl = -1 elif inspect.isfunction(m): # if function take function ttl argument or set -1 by default ttl = getattr(m, 'ttl', -1) elif isinstance(m, DynamicTags): logger.debug('plop') for t in m.iter_tags(): self.tags[t.name] = t logger.debug('Introspected %s with ttl %s.' % (t.name, t.ttl)) continue else: continue logger.debug('Introspected %s with ttl %s.' % (n, ttl)) # finally add the tag self.tags[n] = Tag(n, m, ttl) logger.debug(u'End introspection') @pure def execute_command(self, command): """Execute an arbitrary shell command on the host. :param string command: shell command to run """ # return stdout and stderr mixed in return Popen(command, shell=True, bufsize=-1, stdin=PIPE, stdout=PIPE, stderr=STDOUT).communicate()[0] or None @pure def node_shutdown(self, reboot=True, gracefull=True): """Halt/Reboot the node.""" args = ['/sbin/shutdown'] if reboot: args.append('-r') if gracefull: logger.info(u'Going to reboot the host...') args.append('-f') else: logger.info(u'Going to force the reboot of the host...') args.append('-n') else: # halt args.append('-h -P') if not gracefull: logger.info(u'Going to halt the host...') args.append('-n') else: logger.info(u'Going to force the halt of the host...') args.append('0') return self.execute_command(' '.join(args))
ccnode/host/tags.py 0 → 100644 +170 −0 Original line number Diff line number Diff line """This module acts as a little framework for defining tags in a simple way. Just define a string or a function and it will be introspected and used as a tag value. """ import re import os as os_ import platform as platform_ from multiprocessing import cpu_count from socket import gethostname, gethostbyaddr import psutil from ccnode.tags import Tag, DynamicTags def h(): """Hostname tag.""" hn = gethostname() return gethostbyaddr(hn)[0] or hn h.ttl = 3600 * 24 # one day # CPU related tags def arch(): """Hardware CPU architecture.""" return { u'i386': u'x86', u'i486': u'x86', u'i586': u'x86', u'i686': u'x86', u'x86_64': u'x64', u'': None, }[platform_.machine()] def cpu(): """Number of CPU (core) on the host.""" try: return unicode(cpu_count()) except NotImplementedError: return None def cpuuse(): """CPU usage in percentage.""" return u'%.1f' % psutil.cpu_percent() cpuuse.ttl = 5 # memory related tags def mem(): """Total physical memory available on system.""" return unicode(psutil.avail_phymem() + psutil.used_phymem()) mem.ttl = -1 # FIXME validate ttl def memfree(): """Available physical memory on system.""" return unicode(psutil.avail_phymem()) memfree.ttl = 60 def memused(): """Used physical memory on system.""" return unicode(psutil.used_phymem()) memused.ttl = 60 # disks related tags def disk(): """List of disk devices on the host.""" disk_pattern = re.compile(r'[sh]d[a-z]+') return u' '.join(d for d in os_.listdir( '/sys/block/') if disk_pattern.match(d)) def _disk_tag_value(disk_name): def size(): s = open(os_.path.join('/sys/block', disk_name, 'size')).read().strip() try: s = int(s) if s > 0: return s * 512 else: return None except ValueError: return None return size class DynamicDisks(DynamicTags): def __init__(self): DynamicTags.__init__(self) for d in disk().split(): self.tags.append(Tag(u'disk%s_size' % d, _disk_tag_value(d), 3600)) disks_size = DynamicDisks() # other hardware related tags def chaserial(): """Blade chassis serial number.""" return open('/sys/class/dmi/id/chassis_serial').read().strip() or None def chaasset(): """Blade chassis asset tag.""" return open('/sys/class/dmi/id/chassis_asset_tag').read().strip() or None def hmodel(): """Host hardware model.""" return open('/sys/class/dmi/id/product_name').read().strip() or None def hserial(): """Host hardware serial number.""" return open('/sys/class/dmi/id/product_serial').read().strip() or None def hvendor(): """Host hardware vendor.""" return open('/sys/class/dmi/id/sys_vendor').read().strip() or None def hbios(): """Host BIOS version.""" return u'%s (%s)' % ( open('/sys/class/dmi/id/bios_version').read().strip() or None, open('/sys/class/dmi/id/bios_date').read().strip() or None, ) # Operating system related tags def os(): """Operating system (linux/windows).""" return unicode(platform_.system().lower()) def platform(): """Python platform.platform() info.""" return unicode(platform_.platform()) def uname(): """As uname command (see python os.uname).""" return u' '.join(os_.uname()) or None def uptime(): """Uptime of the system in seconds.""" return open('/proc/uptime').read().split()[0].split(u'.')[0] or None uptime.ttl = 5 def load(): """Average of the number of processes in the run queue over the last 1, 5 and 15 minutes.""" load_ = None try: load_ = u' '.join(unicode(l) for l in os_.getloadavg()) except OSError: pass return load_ load.ttl = 5
ccnode/node.py +20 −8 Original line number Diff line number Diff line Loading @@ -27,7 +27,10 @@ class DefaultHandler(RpcHandler): :param iterable tags: list of tags to return :param iterable noresolve_tags: list of tags to not return """ logger.debug('Tags: %s, %s' % (unicode(tags), unicode(noresolve_tags))) logger.debug('Tags request: %s, %s' % ( unicode(tags), unicode(noresolve_tags), )) tags = set(tags) - set(noresolve_tags) if tags is not None else None Loading @@ -36,6 +39,8 @@ class DefaultHandler(RpcHandler): else: tags = tags & set(self.tags.iterkeys()) profile = time.time() try: result = dict(( t, # tag name dict( Loading @@ -43,6 +48,10 @@ class DefaultHandler(RpcHandler): ttl=self.tags[t].ttl, ), ) for t in tags) except Exception: logger.exception(u'SHould not happend, result.') logger.debug(u'Profiling: %f seconds.' % (time.time() - profile)) logger.debug(u'Returning: %s' % unicode(result)) return result Loading Loading @@ -98,6 +107,9 @@ class Node(Thread): # set handler according to which role was returned by the cc-server if role == u'host': logger.debug(u'Role host affected.') from ccnode.host import Handler as HostHandler # FIXME bad API self.manager._connection.set_handler(HostHandler()) self.role = u'host' elif role == u'hv': logger.debug(u'Role hypervisor affected.') Loading
ccnode/tags.py +20 −1 Original line number Diff line number Diff line import logging from inspect import isfunction logger = logging.getLogger(__name__) class Tag(object): """Class that abstract tags.""" def __init__(self, name, valuable, ttl): Loading @@ -17,6 +21,21 @@ class Tag(object): def value(self): """Returns tag value.""" if isfunction(self._value): try: return self._value() except Exception: logger.exception(u'Calculating tag %s failed:' % self.name) return None return self._value class DynamicTags(object): """Set tags dynamicaly.""" def __init__(self): """Here define the tags.""" self.tags = [] def iter_tags(self): for t in self.tags: yield t