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