2 # Marta Carbone - UniPi
6 # This Method returns a list of tuples formatted as follow:
8 # <key_id> <node_ip> <slicename>
10 # and an authorized_keys file, to be used on a dummynet box.
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
25 # authorized file delimiter string
26 NEWFILE_MARK = "authorized_keys_mark"
28 # Dummynet box private key
29 KEY="/usr/share/dummynet/dbox_key"
31 class GetDummyBoxUsers(Method):
33 Return a list of information about
34 slice, users, user keys, nodes and dummyboxes.
36 This Methods is mean to be used by a DummyBox.
38 Return keys, 0 if there are no users.
41 roles = ['admin', 'pi', 'node']
45 Parameter(int, 'DummyBox id'),
48 returns = Parameter(str, "DummyBox files")
50 def call(self, auth, dummybox_id = None):
52 Get information about users on nodes connected to the DummyBox.
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.
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 "
66 # check for dummynet box existence and get dummyboxes information
67 dummyboxes = Nodes(self.api, {'node_id':dummybox_id, 'node_type':'dummynet'}, ['site_id'])
69 if dummybox_id != None and not dummyboxes:
70 raise PLCInvalidArgument, "No such DummyBox %s" % dummybox_id
72 dummybox = dummyboxes[0]
74 # this method needs authentication
75 assert self.caller is not None
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.
82 # Given a dummybox_id we get the list of connected nodes
83 connected_nodes = NodeTags(self.api, {'value': dummybox_id}, ['node_id'])
86 for i in connected_nodes:
87 node_list.append(i['node_id'])
89 nodes = Nodes(self.api, node_list, ['node_id', 'hostname', 'slice_ids'])
90 if not nodes: return 0
92 # Here nodes should be an array of dict with 'node_id', 'hostname' and 'slice_ids' fields
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
99 # For each node_id we get a list of connected slices
102 # list of connected slices
103 slice_ids = node['slice_ids']
104 if not slice_ids: continue
106 # For each slice we get a list of connected users
107 for slice_id in slice_ids:
109 slice_name = Slices(self.api, {'slice_id': slice_id}, ['name', 'person_ids'])
110 if not slice_name: continue
112 # Given a slice we get a list of users
113 person_ids = slice_name[0]['person_ids']
114 if not person_ids: continue
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
124 for key_id in key_list:
125 key = Keys(self.api, {'key_id': key_id}, ['key'])
127 # Here we have all information we need
128 # to build the authorized key file and
133 # split the key in type/ssh_key/comment
134 splitted_key = k.split(' ',2)
135 uniq_key = splitted_key[0]+" "+splitted_key[1]
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]
142 authorized_keys_dict.update({uniq_key : dbox_key_id})
144 # get the node ip address
145 nodenetworks = Interfaces(self.api, \
146 {'node_id':node['node_id'], 'is_primary':'t'}, ['ip'])
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"
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";
164 # read the central site key
165 # the dummynet public key is located under KEY
168 dbox_key_file = open(pub_key, 'r')
169 dbox_key = dbox_key_file.readline()
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()
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";
182 authorized_keys_file += "\n";
183 # upload the users keys
184 for i in authorized_keys_dict:
186 key_index = str(authorized_keys_dict[i])
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"
192 return user_map+NEWFILE_MARK+"\n"+authorized_keys_file