new omf-oriented plugins
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Tue, 9 Mar 2010 11:48:45 +0000 (11:48 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Tue, 9 Mar 2010 11:48:45 +0000 (11:48 +0000)
new tool for changing files only when needed

nm.py
plugins/omf_resctl.py [new file with mode: 0644]
plugins/omf_vref.py [new file with mode: 0644]
plugins/specialaccounts.py
tools.py

diff --git a/nm.py b/nm.py
index 2884df9..f421769 100755 (executable)
--- a/nm.py
+++ b/nm.py
@@ -86,7 +86,7 @@ def GetSlivers(config, plc):
         data = {}
     #  Invoke GetSlivers() functions from the callback modules
     for module in modules:
-#        logger.log('trigerring GetSlivers callback for module %s'%module.__name__)
+        logger.verbose('trigerring GetSlivers callback for module %s'%module.__name__)
         try:        
             callback = getattr(module, 'GetSlivers')
             callback(data, config, plc)
@@ -170,8 +170,8 @@ def run():
             return getattr(m1,'priority',default_priority) - getattr(m2,'priority',default_priority)
         modules.sort(sort_module_priority)
 
-        logger.verbose('modules priorities and order:')
-        for module in modules: logger.verbose ('%s: %s'%(getattr(module,'priority',default_priority),module.__name__))
+        logger.log('ordered modules:')
+        for module in modules: logger.log ('%s: %s'%(getattr(module,'priority',default_priority),module.__name__))
 
         # Load /etc/planetlab/session
         if os.path.exists(options.session):
diff --git a/plugins/omf_resctl.py b/plugins/omf_resctl.py
new file mode 100644 (file)
index 0000000..1401bc8
--- /dev/null
@@ -0,0 +1,57 @@
+#
+# $Id$
+# $URL$
+#
+# NodeManager plugin - first step of handling omf_controlled slices
+
+"""
+Overwrites the 'resctl' tag of slivers controlled by OMF so sm.py does the right thing
+"""
+
+import subprocess
+
+import tools
+import logger
+
+priority = 11
+
+### xxx this should not be version-dependent
+service_name='omf-resctl-5.3'
+
+def start(options, conf):
+    logger.log("omf_resctl: plugin starting up...")
+
+def GetSlivers(data, conf = None, plc = None):
+    if 'accounts' not in data: 
+        logger.log_missing_data("omf_resctl.GetSlivers",'accounts')
+        return
+
+    try:
+        xmpp_server=data['xmpp']['server']
+    except:
+        # disabled feature - bailing out
+        # xxx might need to clean up more deeply..
+        return
+
+    for sliver in data['slivers']:
+        name=sliver['name']
+        for chunk in sliver['attributes']:
+            if chunk['tagname']=='omf_control':
+                # filenames
+                yaml="/vservers/%s/etc/omf-resctl/omf-resctl.yaml"%name
+                template="%s.in"%yaml
+                # read template and replace
+                template=file(template).read()
+                yaml_contents=template\
+                    .replace('@XMPP_SERVER@',xmpp_server)\
+                    .replace('@NODE_HRN@','default')\
+                    .replace('@SLICE_NAME@',name)
+                changes=tools.replace_file_with_string(yaml,yaml_contents)
+                if changes:
+                    sp=subprocess.Popen(['vserver',name,'exec','service',service_name,'restart'],
+                                        stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
+                    (output,retcod)=sp.communicate()
+                    logger.log("omf_resctl: %s: restarted resource controller (retcod=%r)"%(name,retcod))
+                    logger.log("omf_resctl: got output\n%s"%output)
+                else:
+                    logger.log("omf_resctl: %s: omf_control'ed sliver has no change" % name)
diff --git a/plugins/omf_vref.py b/plugins/omf_vref.py
new file mode 100644 (file)
index 0000000..2b41b52
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# $Id$
+# $URL$
+#
+# NodeManager plugin - first step of handling omf_controlled slices
+
+"""
+Overwrites the 'vref' tag of slivers controlled by OMF so sm.py does the right thing
+Needs to be done the 'sm' module kicks in
+"""
+
+import logger
+
+# do this early, before step 10
+priority = 4
+
+def start(options, conf):
+    logger.log("omf_vref: plugin starting up...")
+
+def GetSlivers(data, conf = None, plc = None):
+    if 'accounts' not in data: 
+        logger.log_missing_data("omf_vref.GetSlivers",'accounts')
+        return
+
+    for sliver in data['slivers']:
+        name=sliver['name']
+        for chunk in sliver['attributes']:
+            if chunk['tagname']=='omf_control':
+                sliver['vref']='omf'
+                logger.log('omf_vref: %s now has vref==omf' % name)
index fb33688..359ff21 100644 (file)
@@ -26,7 +26,7 @@ import tools
 priority = 3
 
 def start(options, conf):
-    logger.log("personkeys: plugin starting up...")
+    logger.log("specialaccounts: plugin starting up...")
 
 def GetSlivers(data, conf = None, plc = None):
     if 'accounts' not in data: 
@@ -50,21 +50,17 @@ def GetSlivers(data, conf = None, plc = None):
         if not os.access(dot_ssh, os.F_OK): os.mkdir(dot_ssh)
         auth_keys = os.path.join(dot_ssh,'authorized_keys')
 
-        logger.log("specialaccounts: new keys = %s" % auth_keys)
-        fd, fname = tempfile.mkstemp('','authorized_keys',dot_ssh)
+        # catenate all keys in string, add newlines just in case (looks like keys already have this, but)
+        auth_keys_contents = '\n'.join(new_keys)+'\n'
 
-        for key in new_keys:
-            os.write(fd,key)
-            os.write(fd,'\n')
-
-        os.close(fd)
-        if os.path.exists(auth_keys): os.unlink(auth_keys)
-        os.rename(fname, auth_keys)
-
-        # set permissions properly
+        changes = tools.replace_file_with_string(auth_keys,auth_keys_contents)
+        if changes:
+            logger.log("specialaccounts: keys file changed: %s" % auth_keys)
+            
+        # always set permissions properly
         os.chmod(dot_ssh, 0700)
         os.chown(dot_ssh, uid,gid)
         os.chmod(auth_keys, 0600)
         os.chown(auth_keys, uid,gid)
 
-        logger.log('specialacounts: installed ssh keys for %s' % name)
+        logger.log('specialaccounts: installed ssh keys for %s' % name)
index 267ec31..80685de 100644 (file)
--- a/tools.py
+++ b/tools.py
@@ -3,18 +3,19 @@
 
 """A few things that didn't seem to fit anywhere else."""
 
-import cPickle
-import errno
 import os
 import pwd
 import tempfile
-import threading
 import fcntl
-import commands
+import errno
+import threading
+import subprocess
+
 import logger
 
 PID_FILE = '/var/run/nm.pid'
 
+####################
 def get_default_if():
     interface = get_if_from_hwaddr(get_hwaddr_from_plnode())
     if not interface: interface = "eth0"
@@ -37,6 +38,8 @@ def get_if_from_hwaddr(hwaddr):
         if dev_hwaddr == hwaddr: return dev
     return None
 
+####################
+# daemonizing
 def as_daemon_thread(run):
     """Call function <run> with no arguments in its own thread."""
     thr = threading.Thread(target=run)
@@ -85,6 +88,8 @@ def fork_as(su, function, *args):
         os._exit(0)
     else: os.waitpid(child_pid, 0)
 
+####################
+# manage files
 def pid_file():
     """We use a pid file to ensure that only one copy of NM is running at a given time.  If successful, this function will write a pid file containing the pid of the current process.  The return value is the pid of the other running process, or None otherwise."""
     other_pid = None
@@ -115,6 +120,28 @@ def write_temp_file(do_write, mode=None, uidgid=None):
     finally: f.close()
     return temporary_filename
 
+# replace a target file with a new contents - checks for changes
+# return True if a change occurred, in which case
+# chown/chmod settings should be taken care of
+def replace_file_with_string (target, new_contents):
+    try:
+        current=file(target).read()
+    except:
+        current=""
+    # xxx if verbose, report diffs...
+    if current==new_contents:
+        return False
+    # overwrite target file
+    f=file(target,'w')
+    f.write(new_contents)
+    f.close()
+    return True
+
+# not needed yet - should that unlink the new file ?
+#def replace_file_with_file (target, new):
+#    return replace_file_with_string (target, file(new).read())
+
+####################
 # utilities functions to get (cached) information from the node
 
 # get node_id from /etc/planetlab/node_id and cache it
@@ -132,10 +159,13 @@ _root_context_arch=None
 def root_context_arch():
     global _root_context_arch
     if not _root_context_arch:
-        _root_context_arch=commands.getoutput("uname -i")
+        sp=subprocess.Popen(["uname","-i"],stdout=subprocess.PIPE)
+        (_root_context_arch,_)=sp.communicate()
+        _root_context_arch=_root_context_arch.strip()
     return _root_context_arch
 
 
+####################
 class NMLock:
     def __init__(self, file):
         logger.log("tools: Lock %s initialized." % file, 2)