review ssh generation for deleted/re-created slivers
[nodemanager.git] / plugins / sliverauth.py
1 #!/usr/bin/python -tt
2 # vim:set ts=4 sw=4 expandtab:
3 #
4 # $Id$
5 # $URL$
6 #
7 # NodeManager plugin for creating credentials in slivers
8 # (*) empower slivers to make API calls throught hmac
9 # (*) also create a ssh key - used by the OMF resource controller 
10 #     for authenticating itself with its Experiment Controller
11 # xxx todo : a config option for turning these 2 things on or off ?
12
13 """
14 Sliver authentication support for NodeManager.
15
16 """
17
18 import os
19 import random
20 import string
21 import tempfile
22 import socket
23
24 import logger
25 import tools
26
27 def start(options, conf):
28     logger.log("sliverauth: (dummy) plugin starting up...")
29
30 def GetSlivers(data, config, plc):
31     if 'OVERRIDES' in dir(config):
32         if config.OVERRIDES.get('sliverauth') == '-1':
33             logger.log("sliverauth:  Disabled", 2)
34             return
35
36     if 'slivers' not in data:
37         logger.log_missing_data("sliverauth.GetSlivers", 'slivers')
38         return
39
40     for sliver in data['slivers']:
41         path = '/vservers/%s' % sliver['name']
42         if not os.path.exists(path):
43             # ignore all non-plc-instantiated slivers
44             instantiation = sliver.get('instantiation','')
45             if instantiation == 'plc-instantiated':
46                 logger.log("sliverauth: plc-instantiated slice %s does not yet exist. IGNORING!" % sliver['name'])
47             continue
48
49         manage_hmac (plc, sliver)
50         manage_sshkey (plc, sliver)
51
52
53 def SetSliverTag(plc, slice, tagname, value):
54     node_id = tools.node_id()
55     slivertags=plc.GetSliceTags({"name":slice,"node_id":node_id,"tagname":tagname})
56     if len(slivertags)==0:
57         # looks like GetSlivers reports about delegated/nm-controller slices that do *not* belong to this node
58         # and this is something that AddSliceTag does not like
59         try:
60             slivertag_id=plc.AddSliceTag(slice,tagname,value,node_id)
61         except:
62             logger.log_exc ("sliverauth.SetSliverTag (probably delegated) slice=%(slice)s tag=%(tagname)s node_id=%(node_id)d"%locals())
63             pass
64     else:
65         slivertag_id=slivertags[0]['slice_tag_id']
66         plc.UpdateSliceTag(slivertag_id,value)
67
68 def find_tag (sliver, tagname):
69     for attribute in sliver['attributes']:
70         # for legacy, try the old-fashioned 'name' as well
71         name = attribute.get('tagname',attribute.get('name',''))
72         if name == tagname:
73             return attribute['value']
74     return None
75
76 def manage_hmac (plc, sliver):
77     hmac = find_tag (sliver, 'hmac')
78
79     if not hmac:
80         # let python do its thing 
81         random.seed()
82         d = [random.choice(string.letters) for x in xrange(32)]
83         hmac = "".join(d)
84         SetSliverTag(plc,sliver['name'],'hmac',hmac)
85         logger.log("sliverauth: %s: setting hmac" % sliver['name'])
86
87     path = '/vservers/%s/etc/planetlab' % sliver['name']
88     if os.path.exists(path):
89         keyfile = '%s/key' % path
90         if (tools.replace_file_with_string(keyfile,hmac,chmod=0400)):
91             logger.log ("sliverauth: (over)wrote hmac into %s " % keyfile)
92
93 # create the key if needed and returns the key contents
94 def generate_sshkey (sliver): 
95     keyfile="/vservers/%s/home/%s/.ssh/id_rsa"%(sliver['name'],sliver['name'])
96     pubfile="%s.pub"%keyfile
97     dotssh=os.path.dirname(keyfile)
98     # create dir if needed
99     if not os.path.isdir (dotssh):
100         os.mkdir (dotssh, 0700)
101         logger.log_call ( [ 'chown', "%s:slices"%(sliver['name']), dotssh ] )
102     if not os.path.isfile (pubfile):
103         comment="%s@%s"%(sliver['name'],socket.gethostname())
104         logger.log_call( [ 'ssh-keygen', '-t', 'rsa', '-N', '', '-f', keyfile , '-C', comment] )
105         os.chmod (keyfile, 0400)
106         logger.log_call ( [ 'chown', "%s:slices"%(sliver['name']), keyfile, pubfile ] )
107     return file(pubfile).read()
108
109 # a sliver can get created, deleted and re-created
110 # the slice having the tag is not sufficient to skip key geneneration
111 def manage_sshkey (plc, sliver):
112     # regardless of whether the tag is there or not, we need to grab the file
113     # if it's lost b/c e.g. the sliver was destroyed we cannot save the tags content
114     ssh_key = generate_sshkey(sliver)
115     old_tag = find_tag (sliver, 'ssh_key')
116     if ssh_key <> old_tag:
117         SetSliverTag(plc, sliver['name'], 'ssh_key', ssh_key)
118         logger.log ("sliverauth: %s: setting ssh_key" % sliver['name'])