167f63cb94df342864e3bd8b4800caa33e76d77e
4 * This file contains gateway functions for RackTables.
5 * A gateway is an external executable, which provides
6 * read-only or read-write access to some external entities.
7 * Each gateway accepts its own list of command-line args
8 * and then reads its stdin for requests. Each request consists
9 * of one line and results in exactly one line of reply.
10 * The replies must have the following syntax:
11 * OK<space>any text up to the end of the line
12 * ERR<space>any text up to the end of the line
17 // This function launches specified gateway with specified
18 // command-line arguments and feeds it with the commands stored
19 // in the second arg as array.
20 // The answers are stored in another array, which is returned
21 // by this function. In the case when a gateway cannot be found,
22 // finishes prematurely or exits with non-zero return code,
23 // a single-item array is returned with the only "ERR" record,
24 // which explains the reason.
25 function queryGateway ($gwname, $questions)
27 $execpath = "./gateways/{$gwname}/main";
30 0 => array ("pipe", "r"),
31 1 => array ("pipe", "w"),
32 2 => array ("file", "/dev/null", "a")
35 $gateway = proc_open ($execpath, $dspec, $pipes);
36 if (!is_resource ($gateway))
37 return array ('ERR proc_open() failed in ' . __FUNCTION__
);
39 // Dialogue starts. Send all questions.
40 foreach ($questions as $q)
41 fwrite ($pipes[0], "$q\n");
46 while (!feof($pipes[1]))
48 $a = fgets ($pipes[1]);
51 // Somehow I got a space appended at the end. Kick it.
52 $answers[] = trim ($a);
56 $retval = proc_close ($gateway);
58 return array ("ERR gateway '${gwname}' returned ${retval}");
62 // This functions returns an array for VLAN list, and an array for port list (both
63 // form another array themselves) and another one with MAC address list.
64 // The ports in the latter array are marked with either VLAN ID or 'trunk'.
65 // We don't sort the port list, as the gateway is believed to have done this already
66 // (or at least the underlying switch software ought to). This is important, as the
67 // port info is transferred to/from form not by names, but by numbers.
68 function getSwitchVLANs ($object_id = 0)
70 global $remote_username;
73 showError ('Invalid object_id', __FUNCTION__
);
76 $objectInfo = getObjectInfo ($object_id);
77 $endpoints = findAllEndpoints ($object_id, $objectInfo['name']);
78 if (count ($endpoints) == 0)
80 showError ('Can\'t find any mean to reach current object. Please either set FQDN attribute or assign an IP address to the object.', __FUNCTION__
);
83 if (count ($endpoints) > 1)
85 showError ('More than one IP address is assigned to this object, please configure FQDN attribute.', __FUNCTION__
);
88 $hwtype = $swtype = 'unknown';
89 foreach (getAttrValues ($object_id, TRUE) as $record)
91 if ($record['name'] == 'SW type' && !empty ($record['value']))
92 $swtype = str_replace (' ', '+', $record['value']);
93 if ($record['name'] == 'HW type' && !empty ($record['value']))
94 $hwtype = str_replace (' ', '+', $record['value']);
96 $endpoint = str_replace (' ', '+', $endpoints[0]);
99 "connect ${endpoint} ${hwtype} ${swtype} ${remote_username}",
104 $data = queryGateway ('switchvlans', $commands);
107 showError ('Failed to get any response from queryGateway() or the gateway died', __FUNCTION__
);
110 if (strpos ($data[0], 'OK!') !== 0)
112 showError ("Gateway failure: ${data[0]}.", __FUNCTION__
);
115 if (count ($data) != count ($commands))
117 showError ("Gateway failure: malformed reply.", __FUNCTION__
);
120 // Now we have VLAN list in $data[1] and port list in $data[2]. Let's sort this out.
121 $tmp = array_unique (explode (';', substr ($data[1], strlen ('OK!'))));
122 if (count ($tmp) == 0)
124 showError ("Gateway succeeded, but returned no VLAN records.", __FUNCTION__
);
128 foreach ($tmp as $record)
130 list ($vlanid, $vlandescr) = explode ('=', $record);
131 $vlanlist[$vlanid] = $vlandescr;
134 foreach (explode (';', substr ($data[2], strlen ('OK!'))) as $pair)
136 list ($portname, $pair2) = explode ('=', $pair);
137 list ($status, $vlanid) = explode (',', $pair2);
138 $portlist[] = array ('portname' => $portname, 'status' => $status, 'vlanid' => $vlanid);
140 if (count ($portlist) == 0)
142 showError ("Gateway succeeded, but returned no port records.", __FUNCTION__
);
146 foreach (explode (';', substr ($data[3], strlen ('OK!'))) as $pair)
148 list ($macaddr, $pair2) = explode ('=', $pair);
151 list ($vlanid, $ifname) = explode ('@', $pair2);
152 $maclist[$ifname][$vlanid][] = $macaddr;
154 return array ($vlanlist, $portlist, $maclist);
157 function setSwitchVLANs ($object_id = 0, $setcmd)
159 global $remote_username;
161 return oneLiner (160); // invalid arguments
162 $objectInfo = getObjectInfo ($object_id);
163 $endpoints = findAllEndpoints ($object_id, $objectInfo['name']);
164 if (count ($endpoints) == 0)
165 return oneLiner (161); // endpoint not found
166 if (count ($endpoints) > 1)
167 return oneLiner (162); // can't pick an address
168 $hwtype = $swtype = 'unknown';
169 foreach (getAttrValues ($object_id, TRUE) as $record)
171 if ($record['name'] == 'SW type' && !empty ($record['value']))
172 $swtype = strtr ($record['value'], ' ', '+');
173 if ($record['name'] == 'HW type' && !empty ($record['value']))
174 $hwtype = strtr ($record['value'], ' ', '+');
176 $endpoint = str_replace (' ', '+', $endpoints[0]);
180 array ("connect ${endpoint} ${hwtype} ${swtype} ${remote_username}", $setcmd)
183 return oneLiner (163); // unknown gateway failure
184 if (strpos ($data[0], 'OK!') !== 0)
185 return oneLiner (164, array ($data[0])); // gateway failure
186 if (count ($data) != 2)
187 return oneLiner (165); // protocol violation
188 // Finally we can parse the response into message array.
190 foreach (split (';', substr ($data[1], strlen ('OK!'))) as $text)
192 if (strpos ($text, 'C!') === 0)
194 $tmp = split ('!', $text);
196 $code = array_shift ($tmp);
197 $log_m[] = count ($tmp) ?
array ('c' => $code, 'a' => $tmp) : array ('c' => $code); // gateway-encoded message
199 elseif (strpos ($text, 'I!') === 0)
200 $log_m[] = array ('c' => 62, 'a' => array (substr ($text, 2))); // generic gateway success
201 elseif (strpos ($text, 'W!') === 0)
202 $log_m[] = array ('c' => 202, 'a' => array (substr ($text, 2))); // generic gateway warning
203 else // All improperly formatted messages must be treated as error conditions.
204 $log_m[] = array ('c' => 166, 'a' => array (substr ($text, 2))); // generic gateway error
209 // Drop a file off RackTables platform. The gateway will catch the file and pass it to the given
212 function gwSendFile ($endpoint, $handlername, $filetext = '')
214 global $remote_username;
215 $tmpfilename = tempnam ('', 'RackTables-sendfile-');
216 $tmpfile = fopen ($tmpfilename, 'wb');
217 fwrite ($tmpfile, $filetext);
219 $endpoint = str_replace (' ', '\ ', $endpoint); // the gateway dispatcher uses read (1) to assign arguments
220 $outputlines = queryGateway
223 array ("submit ${remote_username} ${endpoint} ${handlername} ${tmpfilename}")
225 unlink ($tmpfilename);
226 if ($outputlines == NULL)
227 return oneLiner (163); // unknown gateway failure
228 if (count ($outputlines) != 1)
229 return oneLiner (165); // protocol violation
230 if (strpos ($outputlines[0], 'OK!') !== 0)
231 return oneLiner (164, array ($outputlines[0])); // gateway failure
232 // Being here means having 'OK!' in the response.
233 return oneLiner (66, array ($handlername)); // ignore provided "Ok" text
236 // Query something through a gateway and get some text in return. Return that text.
237 function gwRecvFile ($endpoint, $handlername, &$output)
239 global $remote_username;
240 $tmpfilename = tempnam ('', 'RackTables-sendfile-');
241 $endpoint = str_replace (' ', '\ ', $endpoint); // the gateway dispatcher uses read (1) to assign arguments
242 $outputlines = queryGateway
245 array ("submit ${remote_username} ${endpoint} ${handlername} ${tmpfilename}")
247 $output = file_get_contents ($tmpfilename);
248 unlink ($tmpfilename);
249 if ($outputlines == NULL)
250 return oneLiner (163); // unknown gateway failure
251 if (count ($outputlines) != 1)
252 return oneLiner (165); // protocol violation
253 if (strpos ($outputlines[0], 'OK!') !== 0)
254 return oneLiner (164, array ($outputlines[0])); // gateway failure
255 // Being here means having 'OK!' in the response.
256 return oneLiner (66, array ($handlername)); // ignore provided "Ok" text
259 function gwSendFileToObject ($object_id = 0, $handlername, $filetext = '')
261 global $remote_username;
262 if ($object_id <= 0 or empty ($handlername))
263 return oneLiner (160); // invalid arguments
264 $objectInfo = getObjectInfo ($object_id);
265 $endpoints = findAllEndpoints ($object_id, $objectInfo['name']);
266 if (count ($endpoints) == 0)
267 return oneLiner (161); // endpoint not found
268 if (count ($endpoints) > 1)
269 return oneLiner (162); // can't pick an address
270 $endpoint = str_replace (' ', '+', $endpoints[0]);
271 return gwSendFile ($endpoint, $handlername, $filetext);
274 function gwRecvFileFromObject ($object_id = 0, $handlername, &$output)
276 global $remote_username;
277 if ($object_id <= 0 or empty ($handlername))
278 return oneLiner (160); // invalid arguments
279 $objectInfo = getObjectInfo ($object_id);
280 $endpoints = findAllEndpoints ($object_id, $objectInfo['name']);
281 if (count ($endpoints) == 0)
282 return oneLiner (161); // endpoint not found
283 if (count ($endpoints) > 1)
284 return oneLiner (162); // can't pick an address
285 $endpoint = str_replace (' ', '+', $endpoints[0]);
286 return gwRecvFile ($endpoint, $handlername, $output);