sliverauth generates a sliver ssh keypair and exposes it in the 'ssh_key' tag
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Thu, 24 Jun 2010 15:09:58 +0000 (15:09 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Thu, 24 Jun 2010 15:09:58 +0000 (15:09 +0000)
sliverauth uses replace_file_with_string
replace_file_with_string uses sliverauth's atomic code

plugins/sliverauth.py
tools.py

index e840a4d..15f0142 100644 (file)
@@ -4,7 +4,11 @@
 # $Id$
 # $URL$
 #
-# NodeManager plugin to empower slivers to make API calls
+# NodeManager plugin for creating credentials in slivers
+# (*) empower slivers to make API calls throught hmac
+# (*) also create a ssh key - used by the OMF resource controller 
+#     for authenticating itself with its Experiment Controller
+# xxx todo : a config option for turning these 2 things on or off ?
 
 """
 Sliver authentication support for NodeManager.
@@ -22,22 +26,7 @@ import logger
 import tools
 
 def start(options, conf):
-    logger.log("sliverauth: plugin starting up...")
-
-def SetSliverTag(plc, slice, tagname, value):
-    node_id = tools.node_id()
-    slivertags=plc.GetSliceTags({"name":slice,"node_id":node_id,"tagname":tagname})
-    if len(slivertags)==0:
-        # looks like GetSlivers reports about delegated/nm-controller slices that do *not* belong to this node
-        # and this is something that AddSliceTag does not like
-        try:
-            slivertag_id=plc.AddSliceTag(slice,tagname,value,node_id)
-        except:
-            logger.log ("sliverauth: SetSliverTag - CAUGHT exception for (probably delegated) slice=%(slice)s tag=%(tagname)s node_id=%(node_id)d"%locals())
-            pass
-    else:
-        slivertag_id=slivertags[0]['slice_tag_id']
-        plc.UpdateSliceTag(slivertag_id,value)
+    logger.log("sliverauth: (dummy) plugin starting up...")
 
 def GetSlivers(data, config, plc):
     if 'OVERRIDES' in dir(config):
@@ -58,39 +47,66 @@ def GetSlivers(data, config, plc):
                 logger.log("sliverauth: plc-instantiated slice %s does not yet exist. IGNORING!" % sliver['name'])
             continue
 
-        found_hmac = False
-        for attribute in sliver['attributes']:
-            name = attribute.get('tagname',attribute.get('name',''))
-            if name == 'hmac':
-                found_hmac = True
-                hmac = attribute['value']
-                break
-
-        if not found_hmac:
-            # XXX need a better random seed?!
-            random.seed(time.time())
-            d = [random.choice(string.letters) for x in xrange(32)]
-            hmac = "".join(d)
-            SetSliverTag(plc,sliver['name'],'hmac',hmac)
-            logger.log("sliverauth: setting %s hmac" % sliver['name'])
-
-        path = '/vservers/%s/etc/planetlab' % sliver['name']
-        if os.path.exists(path):
-            keyfile = '%s/key' % path
-            oldhmac = ''
-            if os.path.exists(keyfile):
-                f = open(keyfile,'r')
-                oldhmac = f.read()
-                f.close()
-
-            if oldhmac <> hmac:
-                # create a temporary file in the vserver
-                fd, name = tempfile.mkstemp('','key',path)
-                os.write(fd,hmac)
-                os.close(fd)
-                if os.path.exists(keyfile):
-                    os.unlink(keyfile)
-                os.rename(name,keyfile)
-                logger.log("sliverauth: writing hmac to %s " % keyfile)
-
-            os.chmod(keyfile,0400)
+        manage_hmac (plc, sliver)
+        manage_sshkey (plc, sliver)
+
+
+def SetSliverTag(plc, slice, tagname, value):
+    node_id = tools.node_id()
+    slivertags=plc.GetSliceTags({"name":slice,"node_id":node_id,"tagname":tagname})
+    if len(slivertags)==0:
+        # looks like GetSlivers reports about delegated/nm-controller slices that do *not* belong to this node
+        # and this is something that AddSliceTag does not like
+        try:
+            slivertag_id=plc.AddSliceTag(slice,tagname,value,node_id)
+        except:
+            logger.log_exc ("sliverauth.SetSliverTag (probably delegated) slice=%(slice)s tag=%(tagname)s node_id=%(node_id)d"%locals())
+            pass
+    else:
+        slivertag_id=slivertags[0]['slice_tag_id']
+        plc.UpdateSliceTag(slivertag_id,value)
+
+def find_tag (sliver, tagname):
+    for attribute in sliver['attributes']:
+        # for legacy, try the old-fashioned 'name' as well
+        name = attribute.get('tagname',attribute.get('name',''))
+        if name == tagname:
+            return attribute['value']
+    return None
+
+def manage_hmac (plc, sliver):
+    hmac = find_tag (sliver, 'hmac')
+
+    if not hmac:
+        # let python do its thing 
+        random.seed()
+        d = [random.choice(string.letters) for x in xrange(32)]
+        hmac = "".join(d)
+        SetSliverTag(plc,sliver['name'],'hmac',hmac)
+        logger.log("sliverauth: %s: setting hmac" % sliver['name'])
+
+    path = '/vservers/%s/etc/planetlab' % sliver['name']
+    if os.path.exists(path):
+        keyfile = '%s/key' % path
+        if (tools.replace_file_with_string(keyfile,hmac,chmod=0400)):
+            logger.log ("sliverauth: (over)wrote hmac into %s " % keyfile)
+
+def manage_sshkey (plc, sliver):
+    ssh_key = find_tag (sliver, 'ssh_key')
+    
+    # generate if not present
+    if not ssh_key:
+        # create dir if needed
+        dotssh="/vservers/%s/home/%s/.ssh"%(sliver['name'],sliver['name'])
+        if not os.path.isdir (dotssh):
+            os.mkdir (dotssh, 0700)
+            logger.log_call ( [ 'chown', "%s:slices"%(sliver['name']), dotssh ] )
+        keyfile="%s/id_rsa"%dotssh
+        pubfile="%s.pub"%keyfile
+        if not os.path.isfile (pubfile):
+            logger.log_call( [ 'ssh-keygen', '-t', 'rsa', '-N', '', '-f', keyfile ] )
+            os.chmod (keyfile, 0400)
+            logger.log_call ( [ 'chown', "%s:slices"%(sliver['name']), keyfile, pubfile ] )
+        ssh_key = file(pubfile).read()
+        SetSliverTag(plc, sliver['name'], 'ssh_key', ssh_key)
+        logger.log ("sliverauth: %s: setting ssh_key" % sliver['name'])
index b6a189a..22895c4 100644 (file)
--- a/tools.py
+++ b/tools.py
@@ -3,7 +3,7 @@
 
 """A few things that didn't seem to fit anywhere else."""
 
-import os
+import os, os.path
 import pwd
 import tempfile
 import fcntl
@@ -123,8 +123,11 @@ def write_temp_file(do_write, mode=None, uidgid=None):
     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
+# can handle chmod if requested
+# can also remove resulting file if contents are void, if requested
+# performs atomically:
+#    writes in a tmp file, which is then renamed (from sliverauth originally)
+# returns True if a change occurred, or the file is deleted
 def replace_file_with_string (target, new_contents, chmod=None, remove_if_empty=False):
     try:
         current=file(target).read()
@@ -138,16 +141,17 @@ def replace_file_with_string (target, new_contents, chmod=None, remove_if_empty=
             try: os.unlink(target)
             finally: return True
         return False
-    # overwrite target file
-    f=file(target,'w')
-    f.write(new_contents)
-    f.close()
+    # overwrite target file: create a temp in the same directory
+    path=os.path.dirname(target) or '.'
+    fd, name = tempfile.mkstemp('','repl',path)
+    os.write(fd,new_contents)
+    os.close(fd)
+    if os.path.exists(target):
+        os.unlink(target)
+    os.rename(name,target)
     if chmod: os.chmod(target,chmod)
     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