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