manage hmac slice tag only if slice has enable_hmac tag set
[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():
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         for chunk in sliver['attributes']:
50             if chunk['tagname']=='enable_hmac':
51                 manage_hmac (plc, sliver)
52             elif chunk['tagname']=='omf_control':
53                 manage_sshkey (plc, sliver)
54
55
56 def SetSliverTag(plc, slice, tagname, value):
57     node_id = tools.node_id()
58     slivertags=plc.GetSliceTags({"name":slice,"node_id":node_id,"tagname":tagname})
59     if len(slivertags)==0:
60         # looks like GetSlivers reports about delegated/nm-controller slices that do *not* belong to this node
61         # and this is something that AddSliceTag does not like
62         try:
63             slivertag_id=plc.AddSliceTag(slice,tagname,value,node_id)
64         except:
65             logger.log_exc ("sliverauth.SetSliverTag (probably delegated) slice=%(slice)s tag=%(tagname)s node_id=%(node_id)d"%locals())
66             pass
67     else:
68         slivertag_id=slivertags[0]['slice_tag_id']
69         plc.UpdateSliceTag(slivertag_id,value)
70
71 def find_tag (sliver, tagname):
72     for attribute in sliver['attributes']:
73         # for legacy, try the old-fashioned 'name' as well
74         name = attribute.get('tagname',attribute.get('name',''))
75         if name == tagname:
76             return attribute['value']
77     return None
78
79 def manage_hmac (plc, sliver):
80     hmac = find_tag (sliver, 'hmac')
81
82     if not hmac:
83         # let python do its thing 
84         random.seed()
85         d = [random.choice(string.letters) for x in xrange(32)]
86         hmac = "".join(d)
87         SetSliverTag(plc,sliver['name'],'hmac',hmac)
88         logger.log("sliverauth: %s: setting hmac" % sliver['name'])
89
90     path = '/vservers/%s/etc/planetlab' % sliver['name']
91     if os.path.exists(path):
92         keyfile = '%s/key' % path
93         if (tools.replace_file_with_string(keyfile,hmac,chmod=0400)):
94             logger.log ("sliverauth: (over)wrote hmac into %s " % keyfile)
95
96 # create the key if needed and returns the key contents
97 def generate_sshkey (sliver): 
98 # initial version was storing stuff in the sliver directly
99 #    keyfile="/vservers/%s/home/%s/.ssh/id_rsa"%(sliver['name'],sliver['name'])
100 # we're now storing this in the same place as the authorized_keys, which in turn
101 # gets mounted to the user's home directory in the sliver
102     keyfile="/home/%s/.ssh/id_rsa"%(sliver['name'])
103     pubfile="%s.pub"%keyfile
104     dotssh=os.path.dirname(keyfile)
105     # create dir if needed
106     if not os.path.isdir (dotssh):
107         os.mkdir (dotssh, 0700)
108         logger.log_call ( [ 'chown', "%s:slices"%(sliver['name']), dotssh ] )
109     if not os.path.isfile (pubfile):
110         comment="%s@%s"%(sliver['name'],socket.gethostname())
111         logger.log_call( [ 'ssh-keygen', '-t', 'rsa', '-N', '', '-f', keyfile , '-C', comment] )
112         os.chmod (keyfile, 0400)
113         logger.log_call ( [ 'chown', "%s:slices"%(sliver['name']), keyfile, pubfile ] )
114     return file(pubfile).read().strip()
115
116 # a sliver can get created, deleted and re-created
117 # the slice having the tag is not sufficient to skip key geneneration
118 def manage_sshkey (plc, sliver):
119     # regardless of whether the tag is there or not, we need to grab the file
120     # if it's lost b/c e.g. the sliver was destroyed we cannot save the tags content
121     ssh_key = generate_sshkey(sliver)
122     old_tag = find_tag (sliver, 'ssh_key')
123     if ssh_key <> old_tag:
124         SetSliverTag(plc, sliver['name'], 'ssh_key', ssh_key)
125         logger.log ("sliverauth: %s: setting ssh_key" % sliver['name'])