Skip to content
Snippets Groups Projects
Commit cfb70ccf authored by Anael Beutot's avatar Anael Beutot
Browse files

Host functionalities all implemented as previous ccnode.

parent ab5b4d74
No related branches found
No related tags found
No related merge requests found
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))
"""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
......@@ -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
......@@ -36,13 +39,19 @@ class DefaultHandler(RpcHandler):
else:
tags = tags & set(self.tags.iterkeys())
result = dict((
t, # tag name
dict(
value=self.tags[t].value,
ttl=self.tags[t].ttl,
),
) for t in tags)
profile = time.time()
try:
result = dict((
t, # tag name
dict(
value=self.tags[t].value,
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
......@@ -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.')
......
import logging
from inspect import isfunction
logger = logging.getLogger(__name__)
class Tag(object):
"""Class that abstract tags."""
def __init__(self, name, valuable, ttl):
......@@ -17,6 +21,21 @@ class Tag(object):
def value(self):
"""Returns tag value."""
if isfunction(self._value):
return 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment