Commit | Line | Data |
---|---|---|
b325120a | 1 | <?php |
d33645ff DO |
2 | /* |
3 | * | |
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 | |
13 | * | |
14 | */ | |
15 | ||
16 | ||
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. | |
2da7c9b0 | 25 | function queryGateway ($gwname, $questions) |
d33645ff DO |
26 | { |
27 | $execpath = "./gateways/{$gwname}/main"; | |
d33645ff DO |
28 | $dspec = array |
29 | ( | |
30 | 0 => array ("pipe", "r"), | |
31 | 1 => array ("pipe", "w"), | |
32 | 2 => array ("file", "/dev/null", "a") | |
33 | ); | |
34 | $pipes = array(); | |
2da7c9b0 | 35 | $gateway = proc_open ($execpath, $dspec, $pipes); |
d33645ff | 36 | if (!is_resource ($gateway)) |
4d2e93f2 | 37 | return array ('ERR proc_open() failed in ' . __FUNCTION__); |
d33645ff DO |
38 | |
39 | // Dialogue starts. Send all questions. | |
40 | foreach ($questions as $q) | |
41 | fwrite ($pipes[0], "$q\n"); | |
42 | fclose ($pipes[0]); | |
43 | ||
44 | // Fetch replies. | |
2da7c9b0 | 45 | $answers = array (); |
d33645ff DO |
46 | while (!feof($pipes[1])) |
47 | { | |
48 | $a = fgets ($pipes[1]); | |
49 | if (empty ($a)) | |
50 | continue; | |
075aeb88 DO |
51 | // Somehow I got a space appended at the end. Kick it. |
52 | $answers[] = trim ($a); | |
d33645ff DO |
53 | } |
54 | fclose($pipes[1]); | |
55 | ||
56 | $retval = proc_close ($gateway); | |
57 | if ($retval != 0) | |
58 | return array ("ERR gateway '${gwname}' returned ${retval}"); | |
59 | return $answers; | |
60 | } | |
61 | ||
0a1b1268 | 62 | // This functions returns an array for VLAN list, and an array for port list (both |
18cb9495 | 63 | // form another array themselves) and another one with MAC address list. |
0a1b1268 DO |
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) | |
69 | { | |
70 | global $remote_username; | |
71 | if ($object_id <= 0) | |
72 | { | |
61e269b5 | 73 | showError ('Invalid object_id', __FUNCTION__); |
0a1b1268 DO |
74 | return; |
75 | } | |
76 | $objectInfo = getObjectInfo ($object_id); | |
77 | $endpoints = findAllEndpoints ($object_id, $objectInfo['name']); | |
78 | if (count ($endpoints) == 0) | |
79 | { | |
61e269b5 | 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__); |
0a1b1268 DO |
81 | return NULL; |
82 | } | |
83 | if (count ($endpoints) > 1) | |
84 | { | |
61e269b5 | 85 | showError ('More than one IP address is assigned to this object, please configure FQDN attribute.', __FUNCTION__); |
0a1b1268 DO |
86 | return NULL; |
87 | } | |
88 | $hwtype = $swtype = 'unknown'; | |
24cbe8af | 89 | foreach (getAttrValues ($object_id, TRUE) as $record) |
0a1b1268 DO |
90 | { |
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']); | |
95 | } | |
ee2174dd | 96 | $endpoint = str_replace (' ', '+', $endpoints[0]); |
18cb9495 | 97 | $commands = array |
0a1b1268 | 98 | ( |
ee2174dd | 99 | "connect ${endpoint} ${hwtype} ${swtype} ${remote_username}", |
18cb9495 DO |
100 | 'listvlans', |
101 | 'listports', | |
102 | 'listmacs' | |
0a1b1268 | 103 | ); |
18cb9495 | 104 | $data = queryGateway ('switchvlans', $commands); |
0a1b1268 DO |
105 | if ($data == NULL) |
106 | { | |
61e269b5 | 107 | showError ('Failed to get any response from queryGateway() or the gateway died', __FUNCTION__); |
0a1b1268 DO |
108 | return NULL; |
109 | } | |
110 | if (strpos ($data[0], 'OK!') !== 0) | |
111 | { | |
7cc7b297 | 112 | showError ("Gateway failure: ${data[0]}.", __FUNCTION__); |
0a1b1268 DO |
113 | return NULL; |
114 | } | |
18cb9495 | 115 | if (count ($data) != count ($commands)) |
0a1b1268 | 116 | { |
cd40a2a0 | 117 | showError ("Gateway failure: malformed reply.", __FUNCTION__); |
0a1b1268 DO |
118 | return NULL; |
119 | } | |
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) | |
123 | { | |
61e269b5 | 124 | showError ("Gateway succeeded, but returned no VLAN records.", __FUNCTION__); |
0a1b1268 DO |
125 | return NULL; |
126 | } | |
127 | $vlanlist = array(); | |
128 | foreach ($tmp as $record) | |
129 | { | |
130 | list ($vlanid, $vlandescr) = explode ('=', $record); | |
131 | $vlanlist[$vlanid] = $vlandescr; | |
132 | } | |
133 | $portlist = array(); | |
0a73c02f | 134 | foreach (explode (';', substr ($data[2], strlen ('OK!'))) as $pair) |
0a1b1268 | 135 | { |
0a73c02f DO |
136 | list ($portname, $pair2) = explode ('=', $pair); |
137 | list ($status, $vlanid) = explode (',', $pair2); | |
138 | $portlist[] = array ('portname' => $portname, 'status' => $status, 'vlanid' => $vlanid); | |
0a1b1268 DO |
139 | } |
140 | if (count ($portlist) == 0) | |
141 | { | |
61e269b5 | 142 | showError ("Gateway succeeded, but returned no port records.", __FUNCTION__); |
0a1b1268 DO |
143 | return NULL; |
144 | } | |
18cb9495 DO |
145 | $maclist = array(); |
146 | foreach (explode (';', substr ($data[3], strlen ('OK!'))) as $pair) | |
147 | { | |
148 | list ($macaddr, $pair2) = explode ('=', $pair); | |
149 | if (empty ($pair2)) | |
150 | continue; | |
151 | list ($vlanid, $ifname) = explode ('@', $pair2); | |
152 | $maclist[$ifname][$vlanid][] = $macaddr; | |
153 | } | |
154 | return array ($vlanlist, $portlist, $maclist); | |
0a1b1268 DO |
155 | } |
156 | ||
157 | function setSwitchVLANs ($object_id = 0, $setcmd) | |
158 | { | |
159 | global $remote_username; | |
0a1b1268 | 160 | if ($object_id <= 0) |
f0ff4930 | 161 | return oneLiner (160); // invalid arguments |
0a1b1268 DO |
162 | $objectInfo = getObjectInfo ($object_id); |
163 | $endpoints = findAllEndpoints ($object_id, $objectInfo['name']); | |
164 | if (count ($endpoints) == 0) | |
f0ff4930 | 165 | return oneLiner (161); // endpoint not found |
0a1b1268 | 166 | if (count ($endpoints) > 1) |
f0ff4930 | 167 | return oneLiner (162); // can't pick an address |
0a1b1268 | 168 | $hwtype = $swtype = 'unknown'; |
24cbe8af | 169 | foreach (getAttrValues ($object_id, TRUE) as $record) |
0a1b1268 DO |
170 | { |
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'], ' ', '+'); | |
175 | } | |
15bb23dc | 176 | $endpoint = str_replace (' ', '+', $endpoints[0]); |
0a1b1268 DO |
177 | $data = queryGateway |
178 | ( | |
179 | 'switchvlans', | |
15bb23dc | 180 | array ("connect ${endpoint} ${hwtype} ${swtype} ${remote_username}", $setcmd) |
0a1b1268 DO |
181 | ); |
182 | if ($data == NULL) | |
f0ff4930 | 183 | return oneLiner (163); // unknown gateway failure |
0a1b1268 | 184 | if (strpos ($data[0], 'OK!') !== 0) |
f0ff4930 | 185 | return oneLiner (164, array ($data[0])); // gateway failure |
0a1b1268 | 186 | if (count ($data) != 2) |
f0ff4930 | 187 | return oneLiner (165); // protocol violation |
0a1b1268 | 188 | // Finally we can parse the response into message array. |
f0ff4930 | 189 | $log_m = array(); |
0a1b1268 DO |
190 | foreach (split (';', substr ($data[1], strlen ('OK!'))) as $text) |
191 | { | |
24dcb9d8 DO |
192 | if (strpos ($text, 'C!') === 0) |
193 | { | |
f0ff4930 DO |
194 | $tmp = split ('!', $text); |
195 | array_shift ($tmp); | |
196 | $code = array_shift ($tmp); | |
197 | $log_m[] = count ($tmp) ? array ('c' => $code, 'a' => $tmp) : array ('c' => $code); // gateway-encoded message | |
24dcb9d8 DO |
198 | } |
199 | elseif (strpos ($text, 'I!') === 0) | |
f0ff4930 | 200 | $log_m[] = array ('c' => 62, 'a' => array (substr ($text, 2))); // generic gateway success |
0a1b1268 | 201 | elseif (strpos ($text, 'W!') === 0) |
f0ff4930 | 202 | $log_m[] = array ('c' => 202, 'a' => array (substr ($text, 2))); // generic gateway warning |
0a1b1268 | 203 | else // All improperly formatted messages must be treated as error conditions. |
f0ff4930 | 204 | $log_m[] = array ('c' => 166, 'a' => array (substr ($text, 2))); // generic gateway error |
0a1b1268 | 205 | } |
f0ff4930 | 206 | return $log_m; |
0a1b1268 DO |
207 | } |
208 | ||
f772271a DO |
209 | // FIXME: shouldn't the common code be made into some helper? |
210 | function activateSLBConfig ($object_id = 0, $configtext = '') | |
211 | { | |
212 | global $remote_username; | |
f772271a | 213 | if ($object_id <= 0 or empty ($configtext)) |
2987fc1f | 214 | return oneLiner (160); // invalid arguments |
f772271a DO |
215 | $objectInfo = getObjectInfo ($object_id); |
216 | $endpoints = findAllEndpoints ($object_id, $objectInfo['name']); | |
217 | if (count ($endpoints) == 0) | |
2987fc1f | 218 | return oneLiner (161); // endpoint not found |
f772271a | 219 | if (count ($endpoints) > 1) |
2987fc1f | 220 | return oneLiner (162); // can't pick an address |
f772271a DO |
221 | $hwtype = $swtype = 'unknown'; |
222 | $endpoint = str_replace (' ', '+', $endpoints[0]); | |
06e1c106 | 223 | $tmpfilename = tempnam ('', 'RackTables-slbconfig-'); |
24d97642 | 224 | $tmpfile = fopen ($tmpfilename, 'wb'); |
06e1c106 | 225 | fwrite ($tmpfile, str_replace ("\r", '', $configtext)); |
24d97642 | 226 | fclose ($tmpfile); |
f772271a DO |
227 | $data = queryGateway |
228 | ( | |
229 | 'slbconfig', | |
24d97642 | 230 | array ("connect ${endpoint} ${hwtype} ${swtype} ${remote_username}", "activate ${tmpfilename}") |
f772271a | 231 | ); |
24d97642 | 232 | unlink ($tmpfilename); |
f772271a | 233 | if ($data == NULL) |
2987fc1f | 234 | return oneLiner (163); // unknown gateway failure |
f772271a | 235 | if (strpos ($data[0], 'OK!') !== 0) |
2987fc1f | 236 | return oneLiner (164, array ($data[0])); // gateway failure |
f772271a | 237 | if (count ($data) != 2) |
2987fc1f | 238 | return oneLiner (165); // protocol violation |
f772271a | 239 | // Finally we can parse the response into message array. |
2987fc1f DO |
240 | $log = array ('v' => 2); |
241 | $codemap['ERR'] = 166; // generic gateway error | |
242 | $codemap['OK'] = 62; // generic gateway success | |
24d97642 | 243 | list ($code, $text) = split ('!', $data[1]); |
2987fc1f DO |
244 | $log['m'][] = array ('c' => $codemap[$code], 'a' => array ($text)); |
245 | return $log; | |
f772271a DO |
246 | } |
247 | ||
c030232f DO |
248 | // FIXME: copied and pasted too |
249 | function activateRouterConfig ($object_id = 0, $configtext = '') | |
250 | { | |
251 | global $remote_username; | |
252 | if ($object_id <= 0 or empty ($configtext)) | |
253 | return oneLiner (160); // invalid arguments | |
254 | $objectInfo = getObjectInfo ($object_id); | |
255 | $endpoints = findAllEndpoints ($object_id, $objectInfo['name']); | |
256 | if (count ($endpoints) == 0) | |
257 | return oneLiner (161); // endpoint not found | |
258 | if (count ($endpoints) > 1) | |
259 | return oneLiner (162); // can't pick an address | |
260 | $hwtype = $swtype = 'unknown'; | |
261 | $endpoint = str_replace (' ', '+', $endpoints[0]); | |
262 | $tmpfilename = tempnam ('', 'RackTables-rtrconfig-'); | |
263 | $tmpfile = fopen ($tmpfilename, 'wb'); | |
264 | fwrite ($tmpfile, str_replace ("\r", '', $configtext)); | |
265 | fclose ($tmpfile); | |
266 | $data = queryGateway | |
267 | ( | |
268 | 'rtrconfig', | |
bb0a44e9 | 269 | array ("submit ${remote_username} ${endpoint} ${tmpfilename}") |
c030232f DO |
270 | ); |
271 | unlink ($tmpfilename); | |
272 | if ($data == NULL) | |
273 | return oneLiner (163); // unknown gateway failure | |
274 | if (strpos ($data[0], 'OK!') !== 0) | |
275 | return oneLiner (164, array ($data[0])); // gateway failure | |
276 | if (count ($data) != 2) | |
277 | return oneLiner (165); // protocol violation | |
278 | // Finally we can parse the response into message array. | |
279 | $log = array ('v' => 2); | |
280 | $codemap['ERR'] = 166; // generic gateway error | |
281 | $codemap['OK'] = 62; // generic gateway success | |
282 | list ($code, $text) = split ('!', $data[1]); | |
283 | $log['m'][] = array ('c' => $codemap[$code], 'a' => array ($text)); | |
284 | return $log; | |
285 | } | |
286 | ||
d33645ff | 287 | ?> |