svn keywords
[plcapi.git] / PLC / Methods / GetDummyBoxUsers.py
1 #
2 # Marta Carbone - UniPi 
3 # $Id$
4 # $URL$
5 #
6 # This Method returns a list of tuples formatted as follow:
7
8 #      <key_id> <node_ip> <slicename>
9 #
10 # and an authorized_keys file, to be used on a dummynet box.
11 #
12
13 from PLC.Method import Method                   # base class used to derive methods
14 from PLC.Parameter import Parameter, Mixed      # define input parameters
15 from PLC.Auth import Auth                       # import the Auth parameter
16 from PLC.Faults import *                        # faults library
17 from PLC.Nodes import Node, Nodes               # main class for Nodes
18 from PLC.Slices import Slice, Slices            # main class for Slices
19 from PLC.Keys import Key, Keys                  # main class for Keys
20 from PLC.Persons import Person, Persons         # main class for Persons
21 from PLC.Interfaces import *                    # get the node primary ip address
22 from PLC.NodeTags import *                      # get node connected to a dummynet box
23 from PLC.Accessors.Accessors_dummynetbox import *                       # import dummynet accessors
24
25 # authorized file delimiter string
26 NEWFILE_MARK = "authorized_keys_mark"
27
28 # Dummynet box private key
29 KEY="/usr/share/dummynet/dbox_key"
30
31 class GetDummyBoxUsers(Method):
32         """
33         Return a list of information about
34         slice, users, user keys, nodes and dummyboxes.
35
36         This Methods is mean to be used by a DummyBox.
37
38         Return keys, 0 if there are no users.
39         """
40
41         roles = ['admin', 'pi', 'node']
42
43         accepts = [
44                 Auth(),
45                 Parameter(int, 'DummyBox id'),
46         ]
47
48         returns = Parameter(str, "DummyBox files")
49
50         def call(self, auth, dummybox_id = None):
51                 """
52                 Get information about users on nodes connected to the DummyBox.
53
54                 Given a dummybox_id we get the list of connected nodes
55                 For each node_id we get a list of connected slices
56                 For each slice we get a list of connected users
57                 For each user we get a list of keys that we return to the caller.
58                 """
59
60                 # These variables contain some text to be used
61                 # to format the output files
62                 # port-forwarding should be denied in the main sshd configuration file
63                 ssh_command = "/home/user/dbox.cmd "
64                 ssh_configuration = ",no-port-forwarding,no-agent-forwarding,no-X11-forwarding "
65
66                 # check for dummynet box existence and get dummyboxes information
67                 dummyboxes = Nodes(self.api, {'node_id':dummybox_id, 'node_type':'dummynet'}, ['site_id'])
68
69                 if dummybox_id != None and not dummyboxes:
70                         raise PLCInvalidArgument, "No such DummyBox %s" % dummybox_id
71
72                 dummybox = dummyboxes[0]
73
74                 # this method needs authentication
75                 assert self.caller is not None
76
77                 # XXX check if we have rights to do this operation:
78                 #  - admins can retrive all information they want,
79                 #  - dummyboxes can retrive information regarding their site,
80                 #    nodes and slice account present on their nodes.
81
82                 # Given a dummybox_id we get the list of connected nodes
83                 connected_nodes = NodeTags(self.api, {'value': dummybox_id}, ['node_id'])
84
85                 node_list = []
86                 for i in connected_nodes:
87                         node_list.append(i['node_id'])
88
89                 nodes = Nodes(self.api, node_list, ['node_id', 'hostname', 'slice_ids'])
90                 if not nodes: return 0
91
92                 # Here nodes should be an array of dict with 'node_id', 'hostname' and 'slice_ids' fields
93
94                 user_map = "# Permission file, check here if a user can configure a link\n" # store slice-node information
95                 user_map+= "# Tuples are `owner slice_name' `hostname to reconfigure'\n"
96                 authorized_keys_dict = {}       # user's keys, dictionary
97                 dbox_key_id = 0                 # key_id used to identify users keys in the dummynetbox
98
99                 # For each node_id we get a list of connected slices
100                 for node in nodes:
101
102                         # list of connected slices
103                         slice_ids = node['slice_ids']
104                         if not slice_ids: continue
105
106                         # For each slice we get a list of connected users
107                         for slice_id in slice_ids:
108                                 # field to return
109                                 slice_name = Slices(self.api, {'slice_id': slice_id}, ['name', 'person_ids'])
110                                 if not slice_name: continue
111
112                                 # Given a slice we get a list of users 
113                                 person_ids = slice_name[0]['person_ids']        
114                                 if not person_ids: continue
115
116                                 # For each user we get a list of keys
117                                 for person_id in person_ids:
118                                         # Given a user we get a list of keys
119                                         person_list = Persons(self.api, {'person_id': person_id}, ['person_id','key_ids'])
120                                         person = person_list[0]['person_id']
121                                         key_list = person_list[0]['key_ids']
122                                         if not key_list: continue
123
124                                         for key_id in key_list:
125                                                 key = Keys(self.api, {'key_id': key_id}, ['key'])
126
127                                                 # Here we have all information we need
128                                                 # to build the authorized key file and
129                                                 # the user map file
130
131                                                 k = key[0]['key']
132
133                                                 # split the key in type/ssh_key/comment
134                                                 splitted_key = k.split(' ',2)
135                                                 uniq_key = splitted_key[0]+" "+splitted_key[1]
136
137                                                 # retrieve/create a unique dbox_key_id for this ssh_key
138                                                 if authorized_keys_dict.has_key(uniq_key):
139                                                         dbox_key_id = authorized_keys_dict[uniq_key]
140                                                 else:
141                                                         dbox_key_id+=1
142                                                         authorized_keys_dict.update({uniq_key : dbox_key_id})
143
144                                                 # get the node ip address
145                                                 nodenetworks = Interfaces(self.api, \
146                                                         {'node_id':node['node_id'], 'is_primary':'t'}, ['ip'])
147
148                                                 # append user and slice data to the user_map file       
149                                                 item = str(dbox_key_id)
150                                                 item +=" " + str(nodenetworks[0]['ip'])
151                                                 item +=" " + str(slice_name[0]['name']) + "\n"
152
153                                                 user_map += item
154
155                 # format change for authorized_keys dict
156                 authorized_keys_file="" 
157                 authorized_keys_file += "# generated automatically by GetUsersUpdate.py on the Central Site\n";
158                 authorized_keys_file += "# format file:\n";
159                 authorized_keys_file += '# command="command key_id $SSH_ORIGINAL_COMMAND",ssh_options key_type key comment\n'
160                 authorized_keys_file += "# where command, key_id and ssh_options are filled by the Central Site script\n"
161                 authorized_keys_file += "# and $SSH_ORIGINAL_COMMAND is the command line inserted by the node\n"
162                 authorized_keys_file += "\n";
163
164                 # read the central site key
165                 # the dummynet public key is located under KEY 
166                 try:
167                         pub_key=KEY+".pub"
168                         dbox_key_file = open(pub_key, 'r')
169                         dbox_key = dbox_key_file.readline()
170
171                         # upload the central site public key, used to
172                         # send plcapi commands to the central site
173                         # we use the special key_index = 0 value
174                         authorized_keys_file += "# The Central Site key, it allows to jump some checks on the dbox\n"
175                         authorized_keys_file += "command=\"" + ssh_command + "0";
176                         authorized_keys_file += " $SSH_ORIGINAL_COMMAND\"" + ssh_configuration + dbox_key + "\n"
177                         dbox_key_file.close()
178                 except:
179                         authorized_keys_file += "# The Central Site public key not found, this dummynet box\n";
180                         authorized_keys_file += "# will not accept configuration request coming from the Central Site\n";
181
182                 authorized_keys_file += "\n";
183                 # upload the users keys
184                 for i in authorized_keys_dict:
185                         # index of the key
186                         key_index = str(authorized_keys_dict[i])
187
188                         # create the dummynet box command
189                         authorized_keys_file += "command=\"" + ssh_command + key_index;
190                         authorized_keys_file += " $SSH_ORIGINAL_COMMAND\"" + ssh_configuration + str(i) + "\n"
191
192                 return user_map+NEWFILE_MARK+"\n"+authorized_keys_file