├── README.md ├── glpi.php └── plugin.xml /README.md: -------------------------------------------------------------------------------- 1 | # Discontinued project 2 | 3 | :warning: This project is no more maintenened. As we don't use anymore glpi project, this project is not useful. 4 | You're welcome to fork and continue its life. You can also a check some others projects to manage your IT management 5 | * https://fusionsuite.org/ 6 | * https://snipeitapp.com/ 7 | * https://www.combodo.com/itop 8 | 9 | 10 | # GLPI Ansible 11 | 12 | A PHP script to retrieve [dynamic 13 | inventory](http://docs.ansible.com/ansible/intro_dynamic_inventory.html) for 14 | [Ansible](http://www.ansible.com/) from [GLPI](http://www.glpi-project.org/). 15 | 16 | 17 | ## Requirements 18 | 19 | This script use [PHP](http://php.net) and theses libraries: 20 | * [json](http://php.net/manual/en/json.installation.php); 21 | * [intl](http://php.net/manual/eb/book.intl.php) to do some transliteration. 22 | 23 | ```bash 24 | # To install requirements on Debian/Ubuntu: 25 | sudo apt-get install php5-cli php5-json php5-intl 26 | ``` 27 | 28 | 29 | ## GLPI configuration 30 | 31 | To use this script: 32 | 33 | * Install [Webservices](http://plugins.glpi-project.org/spip.php?article93) plugin; 34 | * Then create a Webservice client: 35 | * Set Ansible server IP address into `IPv4 address range`; 36 | * Webservice `user name` and `password` fields must be left _empty_. 37 | 38 | 39 | ## Installation 40 | 41 | Install this script from sources via Git into Ansible configuration dir: 42 | 43 | ```bash 44 | git clone git@github.com:Webelys/glpi_ansible.git /etc/ansible/glpi_ansible/ 45 | ``` 46 | 47 | To set GLPI inventory as default hosts Ansible file 48 | ```bash 49 | ln -s /etc/ansible/glpi-ansible/glpi.php /etc/ansible/hosts 50 | ``` 51 | 52 | To set GLPI inventory as optional hosts Ansible file 53 | ```bash 54 | ln -s /etc/ansible/glpi_ansible/glpi.php /etc/ansible/glpi 55 | ``` 56 | 57 | Create the configuration file `/etc/ansible/glpi.ini`: 58 | 59 | ```ini 60 | # Ansible external inventory script settings for GLPI 61 | # 62 | 63 | # Define an GLPI user with access to GLPI API which will be used to 64 | # perform required queries to obtain infromation to generate the Ansible 65 | # inventory output. 66 | # 67 | [glpi] 68 | username = "glpi_user" 69 | password = "glpi_password" 70 | url = "http://localhost/glpi/plugins/webservices/rest.php" 71 | ``` 72 | 73 | Note: The user is a real GLPI user must be used, _not_ a Webservice user. 74 | 75 | ## Help - cli mode 76 | 77 | ```bash 78 | Usage: ./glpi.php [options] 79 | 80 | --glpi -g : GLPI "rest.php" webservice URL (default: "https://glpi.webelys.com/plugins/webservices/rest.php") 81 | --username -u : GLPI user name 82 | --password -p : GLPI user password 83 | --list : Return a complete JSON document (default when called by Ansible) 84 | --host [hostname] : [Not implemented yet] Return vars associated to this hostname 85 | --cache [time] : Set duration of local cache (default: "P01D" (P01D = 1 day, PT0S=no cache) 86 | --debug -d : Display debug information (default disabled) 87 | --help -h : display this screen 88 | 89 | Any other options are used for REST call. 90 | All options can be set in glpi.ini file 91 | ``` 92 | 93 | 94 | ## Usage 95 | 96 | ```bash 97 | ansible -i /etc/ansible/glpi Rootentity -m ping 98 | ``` 99 | or 100 | ```bash 101 | ansible Rootentity -m ping 102 | ``` 103 | 104 | 105 | To debug the script: 106 | 107 | ```bash 108 | cd /etc/ansible/ 109 | # Output the cached JSON data, as used by Ansible: 110 | ./glpi --list 111 | 112 | # Reset and output the freshJSON data, as used by Ansible: 113 | ./glpi --list --cache PT0S 114 | 115 | # Show GLPI Webservice requests (debug mode) : 116 | ./glpi -d 117 | 118 | # Show help 119 | ./glpi -h 120 | ``` 121 | 122 | ## Extracted Data 123 | 124 | This script extract: 125 | 126 | * GLPI _Entities_ are translated to Ansible _Groups_ 127 | * GLPI Entities Hierarchy is converted to Ansible Groups _Children_ 128 | * Only GLPI Computer items are extrated as host (FQDN name is used when 129 | _domain_ is set) 130 | 131 | Sample of the JSON output: 132 | 133 | ```json 134 | { 135 | "Rootentity": { 136 | "hosts": [ 137 | "my_computer_1", 138 | "my_computer_3" 139 | ], 140 | "children": [ 141 | "my_child_entity_1" 142 | ] 143 | }, 144 | "my_child_entity_1": { 145 | "hosts": [ 146 | "my_computer_2" 147 | ], 148 | "children": [] 149 | } 150 | } 151 | ``` 152 | -------------------------------------------------------------------------------- /glpi.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | . 22 | 23 | @package glpi-ansible 24 | @author cam.lafit 25 | @copyright Copyright (c) 2015-2015 Webelys team 26 | @license AGPL License 3.0 or (at your option) any later version 27 | http://www.gnu.org/licenses/agpl-3.0-standalone.html 28 | @link http://www.glpi-project.org/ 29 | @link http://docs.ansible.com/ansible/intro_inventory.html 30 | @since 2015 31 | -------------------------------------------------------------------------- 32 | */ 33 | 34 | // ---------------------------------------------------------------------- 35 | // Purpose of file: Test the XML-RPC plugin from Command Line 36 | // ---------------------------------------------------------------------- 37 | 38 | if (!function_exists("json_encode")) { 39 | die("Extension json_encode not loaded\n"); 40 | } 41 | 42 | if (!function_exists("transliterator_transliterate")) { 43 | die("Extension intl not loaded\n"); 44 | } 45 | 46 | $cache_file = sys_get_temp_dir().'/.glpi_ansible_hosts_cache.json'; 47 | 48 | //Load ini configuration 49 | $ini = array(); 50 | $file_ini = dirname($_SERVER["SCRIPT_FILENAME"]).'/glpi.ini'; 51 | if (file_exists($file_ini)) { 52 | $ini = parse_ini_file($file_ini, true); 53 | } 54 | 55 | $longoptions = array( 56 | 'h' => 'help', 57 | 'g' => 'glpi', 58 | 'p' => 'password', 59 | 'u' => 'username', 60 | 'd' => 'debug' 61 | ); 62 | 63 | $options = array(); 64 | if (sizeof($argv)>1) { 65 | //$argv[0] == filename 66 | for ($i = 1; $iadd($cache_interval); 135 | 136 | //Return cached file if not expired 137 | if ($cache_expiration>$now) { 138 | die(file_get_contents($cache_file)); 139 | } 140 | } 141 | 142 | function glpi_request($glpi, $method, $query_datas) 143 | { 144 | global $options; 145 | $query_datas['method'] = $method; 146 | 147 | $query_str = urldecode(http_build_query($query_datas)); 148 | $url_request = $glpi."?".$query_str; 149 | 150 | if (isset($options['debug'])) { 151 | echo "+ Calling '".$method."' on $url_request\n"; 152 | } 153 | 154 | $file = file_get_contents($url_request, false); 155 | if (!$file) { 156 | if (isset($options['debug'])) { 157 | echo "+ No response\n"; 158 | die("{}"); 159 | } 160 | } 161 | 162 | $response = json_decode($file, true); 163 | 164 | if (!is_array($response)) { 165 | if (isset($options['debug'])) { 166 | echo $file; 167 | echo ("+ Bad response\n"); 168 | } 169 | die("{}"); 170 | } 171 | 172 | if (isset($response['faultCode'])) { 173 | if (isset($options['debug'])) { 174 | echo "REST error(".$response['faultCode']."): ".$response['faultString']."\n"; 175 | } 176 | die("{}"); 177 | } 178 | 179 | return $response; 180 | } 181 | 182 | // Login to GLPI 183 | $response = glpi_request($options['glpi'], 'glpi.doLogin', array('login_name' => $options['username'], 'login_password' => $options['password'])); 184 | 185 | if (!is_array($response)) { 186 | if (isset($options['debug'])) { 187 | echo $file; 188 | echo "+ Bad response\n"; 189 | } 190 | die("{}"); 191 | } 192 | 193 | if (!isset($response['session'])) { 194 | if (isset($options['debug'])) { 195 | echo "Bad Login/Password\nNo session set"; 196 | } 197 | die("{}"); 198 | } 199 | 200 | $session = $response['session']; 201 | 202 | //Get Profiles and Set super-admin as current 203 | $response = glpi_request($options['glpi'], 'glpi.listMyProfiles', array('session' => $session)); 204 | foreach ($response as $profile) { 205 | if (strtolower($profile['name']) == 'super-admin' && $profile['current'] != 1) { 206 | $response = glpi_request($options['glpi'], 'glpi.setMyProfile', array('session' => $session,'profile' => $profile['id'])); 207 | break; 208 | } 209 | } 210 | 211 | //Entities listing 212 | $start = 0; 213 | $limit = 20; 214 | $entities = array(); 215 | do { 216 | $response = glpi_request($options['glpi'], 'glpi.listEntities', array('session' => $session,'start' => $start, 'limit' => $limit)); 217 | if (!empty($response)) { 218 | foreach ($response as $row) { 219 | $row_entities = explode('>', $row['completename']); 220 | $entities[$row['id']] = array( 221 | 'id' => $row['id'], 222 | 'name' => trim(end($row_entities)), 223 | 'parent' => trim(prev($row_entities)), 224 | 'children' => array() 225 | ); 226 | } 227 | } 228 | $start += $limit; 229 | } while (!empty($response)); 230 | //Loop all entities 231 | foreach ($entities as $entity_id => $entity) { 232 | //Set children 233 | foreach ($entities as $key => $parent) { 234 | if ($parent['name'] == $entity['parent']) { 235 | $entities[$key]['children'][] = $entity['id']; 236 | } 237 | } 238 | } 239 | 240 | //Domains Listing 241 | $start = 0; 242 | $limit = 20; 243 | $domains = array(); 244 | do { 245 | $response = glpi_request($options['glpi'], 'glpi.listDropdownValues', array('session' => $session, 'dropdown' =>'domains','start' => $start, 'limit' => $limit)); 246 | if (!empty($response)) { 247 | foreach ($response as $row) { 248 | if (isset($row['id']) && isset($row['name'])) { 249 | $domains[$row['id']] = $row['name']; 250 | } 251 | } 252 | } 253 | $start += $limit; 254 | } while (!empty($response)); 255 | 256 | //Get Computers 257 | $start = 0; 258 | $limit = 20; 259 | $computers = array(); 260 | do { 261 | $response = glpi_request($options['glpi'], 'glpi.listObjects', array('session' => $session, 'itemtype' => 'Computer', 'start' => $start, 'limit' => $limit)); 262 | if (!empty($response)) { 263 | $computers = array_merge($computers, $response); 264 | } 265 | $start += $limit; 266 | } while (!empty($response)); 267 | 268 | 269 | //Computer Detail 270 | foreach ($computers as $key => $computer) { 271 | 272 | $response = glpi_request($options['glpi'], 'glpi.getObject', array('session' => $session, 'itemtype' => 'Computer', 'id' => $computer['id'])); 273 | 274 | if (!empty($response)) { 275 | $computers[$key] = array_merge($computers[$key], $response); 276 | $computers[$key]['entity'] = $entities[$computers[$key]['entities_id']]; 277 | $computers[$key]['domain'] = (isset($computers[$key]['domains_id']) && !empty($computers[$key]['domains_id']) && isset($domains[$computers[$key]['domains_id']])) ? $domains[$computers[$key]['domains_id']] : ""; 278 | } 279 | } 280 | 281 | if (isset($options['debug'])) { 282 | echo print_r($entities, true); 283 | echo print_r($computers, true); 284 | } 285 | 286 | $response = glpi_request($options['glpi'], 'glpi.doLogout', array('session' => $session)); 287 | 288 | $inventory = array(); 289 | foreach ($entities as $entity) { 290 | 291 | //Set Group 292 | $entity['name'] = transliterator_transliterate('Any-Latin; Latin-ASCII;', $entity['name']); 293 | $entity['name'] = str_replace(' ', '', $entity['name']); 294 | $inventory[$entity['name']] = array('hosts' => array(), 'children' => array()); 295 | //List computer 296 | foreach ($computers as $computer) { 297 | if ($computer['entity']['id'] == $entity['id']) { 298 | $fqdn = str_replace(' ', '', $computer['name']).(!empty($computer['domain']) ? ".".$computer['domain'] : ""); 299 | //Prevent duplicate host 300 | if (!in_array($fqdn, $inventory[$entity['name']]['hosts'])) { 301 | $inventory[$entity['name']]['hosts'][] = $fqdn; 302 | } 303 | } 304 | } 305 | //Set group children 306 | if (!empty($entity['children'])) { 307 | foreach ($entity['children'] as $child_id) { 308 | $inventory[$entity['name']]['children'][] = $entities[$child_id]['name']; 309 | } 310 | } 311 | 312 | // Remove duplicate host 313 | $inventory[$entity['name']]['hosts'] = array_unique($inventory[$entity['name']]['hosts']); 314 | } 315 | 316 | //Return list json data 317 | if (isset($options['list'])) { 318 | $list_json = json_encode($inventory); 319 | file_put_contents($cache_file, $list_json); 320 | die($list_json); 321 | } 322 | -------------------------------------------------------------------------------- /plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | GLpi to Ansible 3 | glpi_ansible 4 | beta 5 | 6 | 7 | 8 | Import inventory from GLPI to Ansible hosts file 9 | Importer l'inventaire GLPI dans Ansible 10 | 11 | 12 | Import inventory from GLPI to Ansible hosts file 13 | Importer l'inventaire GLPI dans Ansible 14 | 15 | 16 | https://github.com/Webelys/glpi_ansible 17 | https://github.com/Webelys/glpi_ansible/archive/master.zip 18 | https://github.com/Webelys/glpi_ansible/issues 19 | https://github.com/Webelys/glpi_ansible 20 | 21 | Camille Lafitte (Webelys) 22 | 23 | 24 | 25 | 0.2 26 | 0.80 27 | 28 | 29 | 0.2 30 | 0.90 31 | 32 | 33 | 34 | fr_FR 35 | en_US 36 | 37 | GPL v3 38 | 39 | 40 | inventory 41 | 42 | 43 | inventaire 44 | 45 | 46 | 47 | 48 | --------------------------------------------------------------------------------