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