r2098 + initial router management prototype
[racktables] / inc / gateways.php
CommitLineData
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 25function 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.
68function 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
157function 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?
210function 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
249function 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',
269 array ("submit ${endpoint} ${remote_username} ${tmpfilename}")
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?>