# $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.
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):
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'])
"""A few things that didn't seem to fit anywhere else."""
-import os
+import os, os.path
import pwd
import tempfile
import fcntl
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()
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