Skip to content

Commit 9a5f0b9

Browse files
committed
Added devices API controller phpipam#1173
1 parent ac4dc1e commit 9a5f0b9

File tree

3 files changed

+374
-0
lines changed

3 files changed

+374
-0
lines changed

Diff for: api/controllers/Common.php

+1
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,7 @@ protected function remap_keys ($result = null, $controller = null) {
745745
// special keys for POST / PATCH
746746
if ($_SERVER['REQUEST_METHOD']=="POST" || $_SERVER['REQUEST_METHOD']=="PATCH") {
747747
if($this->_params->controller=="tools" && $this->_params->id=="devices") { $this->keys['hostname'] = "dns_name"; }
748+
if($this->_params->controller=="devices" ) { $this->keys['hostname'] = "dns_name"; }
748749
}
749750

750751
// POST / PATCH

Diff for: api/controllers/Devices.php

+372
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
<?php
2+
3+
/**
4+
* phpIPAM API class to work with devices.
5+
*
6+
*
7+
*/
8+
class Devices_controller extends Common_api_functions {
9+
10+
/**
11+
* _params provided.
12+
*
13+
* @var mixed
14+
*/
15+
public $_params;
16+
17+
/**
18+
* Database object.
19+
*
20+
* @var mixed
21+
*/
22+
protected $Database;
23+
24+
/**
25+
* Response.
26+
*
27+
* @var mixed
28+
*/
29+
protected $Response;
30+
31+
/**
32+
* Master Tools object.
33+
*
34+
* @var mixed
35+
*/
36+
protected $Tools;
37+
38+
/**
39+
* Main Admin class.
40+
*
41+
* @var mixed
42+
*/
43+
protected $Admin;
44+
45+
/**
46+
* Main Subnets class.
47+
*
48+
* @var mixed
49+
*/
50+
protected $Subnets;
51+
52+
/**
53+
* Default fields to search.
54+
*
55+
* @var mixed
56+
*/
57+
protected $default_search_fields = ['hostname','ip_addr','description'];
58+
59+
60+
/**
61+
* __construct function.
62+
*
63+
* @param class $Database
64+
* @param class $Tools
65+
* @param mixed $params // post/get values
66+
* @param class $Response
67+
*/
68+
public function __construct($Database, $Tools, $params, $Response) {
69+
$this->Database = $Database;
70+
$this->Response = $Response;
71+
$this->Tools = $Tools;
72+
$this->_params = $params;
73+
74+
// init required objects
75+
$this->init_object('Admin', $Database);
76+
$this->init_object('Subnets', $Database);
77+
78+
// set valid keys
79+
$this->set_valid_keys("devices");
80+
}
81+
82+
83+
84+
85+
86+
/**
87+
* Returns json encoded options and version
88+
*
89+
* @access public
90+
* @return void
91+
*/
92+
public function OPTIONS () {
93+
// validate
94+
$this->validate_options_request();
95+
96+
// get api
97+
$app = $this->Tools->fetch_object('api', 'app_id', $this->_params->app_id);
98+
99+
// methods
100+
$result = array();
101+
$result['methods'] = array(
102+
array("href"=>"/api/".$this->_params->app_id."/devices/", "methods"=>array(array("rel"=>"options", "method"=>"OPTIONS"))),
103+
array("href"=>"/api/".$this->_params->app_id."/devices/search/{search_term}", "methods"=>array(array("rel"=>"search", "method"=>"GET"))),
104+
array("href"=>"/api/".$this->_params->app_id."/devices/{id}/", "methods"=>array(array("rel"=>"read", "method"=>"GET"),
105+
array("rel"=>"create", "method"=>"POST"),
106+
array("rel"=>"update", "method"=>"PATCH"),
107+
array("rel"=>"delete", "method"=>"DELETE"))),
108+
);
109+
# Response
110+
return array('code'=>200, 'data'=>$result);
111+
}
112+
113+
114+
115+
116+
117+
118+
/**
119+
* GET devices functions
120+
*
121+
* ID can be:
122+
* - / // returns all devices
123+
* - /{id}/ // returns device details
124+
* - /{id}/{subnets}/ // returns all subnets attached to device
125+
* - /{id}/{addresses}/ // returns all IP addresses attached to device
126+
* - /search/{search_q}/ // searches for devices
127+
*
128+
* @access public
129+
* @return void
130+
*/
131+
public function GET () {
132+
// all objects
133+
if (!isset($this->_params->id)) {
134+
// fetch all devices
135+
$result = $this->Tools->fetch_all_objects('devices', 'id');
136+
// result
137+
if(!$result) { return $this->Response->throw_exception(200, "No devices configured"); }
138+
else { return array('code'=>200, 'data'=>$this->prepare_result($result, 'devices', true, false)); }
139+
}
140+
// parameters are set
141+
else {
142+
// search for devices
143+
if ($this->_params->id == 'search') {
144+
// verify that search params are set
145+
if (isset($this->_params->id2)) {
146+
// set query
147+
$base_query = "SELECT * from `devices` where ";
148+
149+
# Search all custom fields
150+
$cfs = array_keys($this->Tools->fetch_custom_fields('devices'));
151+
152+
# Merge default fields with custom fields
153+
$search_fields = array_merge($cfs, $this->default_search_fields);
154+
155+
# Using the search fields, build a string to query parameters chained together with " or "
156+
$search_term = $this->_params->id2;
157+
$extended_query = implode(' or ', array_map(
158+
function ($k) {
159+
return " `$k` like ? ";
160+
}, $search_fields));
161+
162+
# Set up an array of parameters to match the query we built
163+
$query_params = array_fill(0, count($search_fields), "%$search_term%");
164+
165+
# Put together with the base query
166+
$search_query = $base_query . $extended_query;
167+
168+
# Search query
169+
$result = $this->Database->getObjectsQuery($search_query, $query_params);
170+
171+
// result
172+
if(!$result) { return $this->Response->throw_exception(200, "No devices found"); }
173+
else { return array('code'=>200, 'data'=>$this->prepare_result($result, 'devices', true, false)); }
174+
}
175+
else {
176+
$this->Response->throw_exception(400, 'No search term given');
177+
}
178+
}
179+
// not search
180+
else {
181+
// Id must be numeric
182+
if (!is_numeric($this->_params->id)) { $this->Response->throw_exception(400, 'ID must be numeric'); }
183+
184+
// additional parameter is set?
185+
if(isset($this->_params->id2)) {
186+
// addresses
187+
if ($this->_params->id2 == 'addresses') {
188+
$result = $this->Tools->fetch_multiple_objects("ipaddresses", 'switch', $this->_params->id, 'id', true);
189+
}
190+
// subnets
191+
elseif ($this->_params->id2 == 'subnets') {
192+
$result = $this->Tools->fetch_multiple_objects("subnets", 'device', $this->_params->id, 'id', true);
193+
}
194+
// error
195+
else {
196+
$this->Response->throw_exception(400, 'Invalid parameters');
197+
}
198+
}
199+
// device details
200+
else {
201+
// fetch device
202+
$result = $this->Tools->fetch_object('devices', 'id', $this->_params->id);
203+
if (!$result) { $this->Response->throw_exception(404, 'Device not found'); }
204+
}
205+
206+
// all ok, prepare result
207+
if($result === false) { return $this->Response->throw_exception(200, "No ".$this->_params->id2." found"); }
208+
else { return array('code'=>200, 'data'=>$this->prepare_result($result, 'devices', true, false)); }
209+
}
210+
}
211+
}
212+
213+
214+
215+
216+
217+
/**
218+
* HEAD, no response.
219+
*/
220+
public function HEAD () {
221+
return $this->GET ();
222+
}
223+
224+
225+
226+
227+
/**
228+
* Creates new device
229+
*
230+
* /devices/
231+
*
232+
* @method POST
233+
*/
234+
public function POST () {
235+
# Put incoming keys in order
236+
$this->remap_keys ();
237+
238+
# check for valid keys
239+
$values = $this->validate_keys ();
240+
241+
# validations
242+
$this->validate_device_type ();
243+
244+
# only 1 parameter ?
245+
if (sizeof($values) == 1) { $this->Response->throw_exception(400, 'No parameters'); }
246+
247+
// provide default params if they are not set
248+
if(!isset($this->_params->sections)) {
249+
$sections_json = $this->get_all_sections_delimited ();
250+
if($sections_json!==false) {
251+
$values['sections'] = $sections_json;
252+
}
253+
}
254+
255+
// execute update
256+
if (!$this->Admin->object_modify('devices', 'add', '', $values)) {
257+
{ $this->Response->throw_exception(500, 'Device creation failed'); }
258+
}
259+
else {
260+
//set result
261+
return array("code"=>201, "message"=>"Device created", "id"=>$this->Admin->lastId, "location"=>"/api/".$this->_params->app_id."/devices/".$this->Admin->lastId."/");
262+
}
263+
}
264+
265+
266+
267+
268+
269+
270+
/**
271+
* Update device details
272+
*
273+
* @method PATCH
274+
*/
275+
public function PATCH (){
276+
# Put incoming keys back in order
277+
$this->remap_keys();
278+
279+
# validations
280+
$this->validate_device_type();
281+
282+
# validate and prepare keys
283+
$values = $this->validate_keys();
284+
285+
# only 1 parameter ?
286+
if (sizeof($values) == 1) { $this->Response->throw_exception(400, 'No parameters'); }
287+
288+
# execute update
289+
if (!$this->Admin->object_modify('devices', 'edit', 'id', $values)) {
290+
$this->Response->throw_exception(500, 'Device edit failed');
291+
} else {
292+
// fetch the updated object and hand it back to the client
293+
return array("code"=>200, "message"=>"Device updated", "id"=>$this->Admin->lastId, "location"=>"/api/".$this->_params->app_id."/devices/".$values['id']."/");
294+
}
295+
}
296+
297+
298+
299+
300+
301+
302+
/**
303+
* Delete existing device
304+
*
305+
* @method DELETE
306+
*/
307+
public function DELETE () {
308+
# set variables for delete
309+
$values = array();
310+
$values['id'] = $this->_params->id;
311+
312+
# check that section exists
313+
if($this->Admin->fetch_object ("devices", "id", $this->_params->id)===false)
314+
{ $this->Response->throw_exception(404, "Device does not exist"); }
315+
316+
# execute delete
317+
if (!$this->Admin->object_modify('devices', 'delete', 'id', $values)) {
318+
$this->Response->throw_exception(500, 'Device delete failed');
319+
}
320+
else {
321+
// delete all references
322+
$this->Admin->remove_object_references('ipaddresses', 'switch', $this->_params->id);
323+
324+
// set result
325+
return array("code"=>200, "message"=>"Device deleted");
326+
}
327+
}
328+
329+
330+
331+
332+
333+
334+
/**
335+
* Validate device type
336+
*
337+
* @method validate_device_type
338+
* @return [type] [description]
339+
*/
340+
private function validate_device_type() {
341+
if (isset($this->_params->type)) {
342+
// numeric
343+
if (!is_numeric($this->_params->type)) {
344+
$this->Response->throw_exception(400, 'Invalid devicetype identifier');
345+
}
346+
// check
347+
if ($this->Tools->fetch_object('deviceTypes', 'id', $this->_params->type) === false) {
348+
$this->Response->throw_exception(400, 'Device type does not exist');
349+
}
350+
}
351+
}
352+
353+
/**
354+
* Create delimited string from all sections for default permissions
355+
*
356+
* @method get_all_sections_delimited
357+
* @return [type] [description]
358+
*/
359+
private function get_all_sections_delimited () {
360+
$sections = $this->Admin->fetch_all_objects ("sections");
361+
// reformat
362+
if($sections!==false) {
363+
$sections_all = array ();
364+
foreach ($sections as $s) {
365+
$sections_all[$s->id] = $s->id;
366+
}
367+
$sections = implode(";",$sections_all);
368+
}
369+
// return
370+
return $sections;
371+
}
372+
}

Diff for: misc/CHANGELOG

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
DELETE /subnets/{id}/permissions/ // removes permissions
6767
PATCH /subnets/{id}/permissions/ // sets subnet permissions (?grouname1=ro&groupname2=3&43=1)
6868
+ New controller Prefix;
69+
+ New controller Devices;
6970
+ New subcontrollers:
7071
+ /tools/nat/
7172
+ /tools/racks/

0 commit comments

Comments
 (0)