diff --git a/public_html/deployment/classes/deploy-foreman.class.php b/public_html/deployment/classes/deploy-foreman.class.php index 172d6eaa1b8543fb884dda9b6785ed2283f43063..08bbad588db1b4fa958bd8c19790bd6b4506455a 100644 --- a/public_html/deployment/classes/deploy-foreman.class.php +++ b/public_html/deployment/classes/deploy-foreman.class.php @@ -1,10 +1,14 @@ <?php - /** * deployForeman * * foreman access to API * + * @example + * $oForeman=new deployForeman($this->_aConfig['foreman']); + * $aForemanHostgroups=$oForeman->getHostgroups(); + * or + * $aForemanHostgroups=$oForeman->getHostgroups(array('id'=>11)); * * @author hahn */ @@ -12,9 +16,27 @@ class deployForeman { protected $_aCfg=array(); - protected $_sApi=false; - protected $_sApiUser=false; - protected $_sApiPassword=false; + /** + * alloews methods and prefixes for methods + * @var array + */ + protected $_aAllowedMethods=array( + 'GET'=>'get', + 'POST'=>'create', + 'PUT'=>'update', + 'DELETE'=>'delete' + ); + + protected $_aApiUrls=array( + 'hostgroups'=>'hostgroups/', + ); + + protected $_aRequest=array(); + + + // ---------------------------------------------------------------------- + // constructor + // ---------------------------------------------------------------------- public function __construct($aCfg) { @@ -24,9 +46,6 @@ class deployForeman { } $this->_aCfg=$aCfg; - $this->_sApi=$aCfg['api']; - $this->_sApiUser=array_key_exists('user', $aCfg) ? $aCfg['user'] : false; - $this->_sApiPassword=array_key_exists('password', $aCfg) ? $aCfg['password'] : false; return true; } // ---------------------------------------------------------------------- @@ -39,46 +58,127 @@ class deployForeman { * @param string $sLevel warnlevel of the given message * @return bool */ - private function log($sMessage, $sLevel = "info") { + protected function log($sMessage, $sLevel = "info") { global $oCLog; return $oCLog->add(basename(__FILE__) . " class " . __CLASS__ . " - " . $sMessage, $sLevel); } /** - * make an http get request and return the response body + * helper function ... get the METHOD by scanning function and search for + * it in _aAllowedMethods + * i.e. "getHostname" --> returns GET * - * @param string $url url for Foreman API - * @param string $method method; one of GET|POST|PUT|DELETE - * @param array $aPostData Post data (arrray [key]=>[value])) - * @param integer $iTimeout + * @return type + */ + protected function _getMethod(){ + $sReturn=''; + foreach ($this->_aAllowedMethods as $sMethod=>$sPrefix){ + if (strpos($this->_aRequest['function'], $sPrefix)===0){ + $sReturn=$sMethod; + continue; + } + } + if (!$sReturn){ + die("ERROR in ".__CLASS__."::".__FUNCTION__.": function ".$this->_aRequest['function']." does not map to a valid method."); + } + return $sReturn; + } + + + /** + * generate an url for foreman API request based on option keys + * - function + * - id + * - more + * + * TODO: multiple items with ids + * POST /api/compute_profiles/:compute_profile_id/compute_resources/:compute_resource_id/compute_attributes + * + * @param type $aOptions * @return string */ + protected function _generateUrl(){ + $sFunction=strtolower($this->_aRequest['function']); + foreach (array_values($this->_aAllowedMethods) as $sMethod){ + $sFunction=preg_replace('/^'.$sMethod.'/i', '', $sFunction); + } + if (!array_key_exists($sFunction, $this->_aApiUrls)){ + die("ERROR in ".__CLASS__."::".__FUNCTION__.": no API method found for function [".$aOptions['function']."]."); + } + $sReturn=$this->_aApiUrls[$sFunction]; + + if (array_key_exists('id', $this->_aRequest)){ + $sReturn.=(int)$aOptions['id'].'/'; + } + if (array_key_exists('more', $this->_aRequest)){ + $sReturn.=$aOptions['more'].'/'; + } + return $sReturn; + } - private function _httpCall($url, $method='GET', $aPostData = false, $iTimeout = 5) { - $this->log(__FUNCTION__ . " start"); + /** + * add parameter for search and paging in an foreman API URL + * + * @return string + */ + protected function _generateParams(){ + $sUrl=$this->_aRequest['url']; + $sReturn=$sUrl.(strpos($sUrl, '?') ? '' : '?'); + + // TODO: "sort by" and "sort order" ... need to be added here ... somehow + foreach(array('page', 'per_page', 'search') as $sParam){ + if (array_key_exists($sParam, $this->_aRequest)){ + $sReturn.='&'.$sParam.'='.urlencode($this->_aRequest[$sParam]); + } + } + return $sReturn; + } + /** + * make an http get request and return the response body + * it is called by _makeRequest + * $aRequest contains subkeys + * - url + * - method; one of GET|POST|PUT|DELETE + * - postdata; for POST only + * + * @param array $aRequest arrayurl for Foreman API + * @return string + */ + protected function _httpCall($aRequest=false, $iTimeout = 5) { + if ($aRequest){ + $this->_aRequest=$aRequest; + } + // $url, $method='GET', $aPostData = false, $iTimeout = 5 + $this->log(__FUNCTION__ . " start <pre>".print_r($this->_aRequest,1)."</pre>"); if (!function_exists("curl_init")) { die("ERROR: PHP CURL module is not installed."); } - $sFullUrl=$this->_sApi.$url; - $this->log(__FUNCTION__ . " ".$method." $sFullUrl"); + + $sApiUrl=$this->_aCfg['api']; + $sApiUser=array_key_exists('user', $this->_aCfg) ? $this->_aCfg['user'] : false; + $sApiPassword=array_key_exists('password', $this->_aCfg) ? $this->_aCfg['password'] : false; + + $sFullUrl=$sApiUrl.$this->_aRequest['url']; + $this->log(__FUNCTION__ . " ".$this->_aRequest['method']." $sFullUrl"); $ch = curl_init($sFullUrl); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); - if ($method==='POST'){ - curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostData); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->_aRequest['method']); + if ($this->_aRequest['method']==='POST'){ + curl_setopt($ch, CURLOPT_POSTFIELDS, $this->_aRequest['postdata']); } curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($ch, CURLOPT_TIMEOUT, $iTimeout); curl_setopt($ch, CURLOPT_USERAGENT, 'IML Deployment GUI :: ' . __CLASS__); - if ($this->_sApiUser){ - curl_setopt($ch, CURLOPT_USERPWD, $this->_sApiUser.":".$this->_sApiPassword); + if ($sApiUser){ + curl_setopt($ch, CURLOPT_USERPWD, $sApiUser.":".$sApiPassword); } + $res = curl_exec($ch); $aReturn=array('info'=>curl_getinfo($ch), 'error'=>curl_error($ch)); curl_close($ch); - $this->log(__FUNCTION__ . " done url: $url"); + $this->log(__FUNCTION__ . " status ".$aReturn['info']['http_code'].' '.$this->_aRequest['method']." $sFullUrl"); $sHeader=substr($res, 0, $aReturn['info']['header_size']); $aReturn['header']=explode("\n", $sHeader); @@ -102,31 +202,41 @@ class deployForeman { * - _OK: flag if result is OK and complete * - _status: info * - * @param string $url url for Foreman API - * @param string $method method; one of GET|POST|PUT|DELETE - * @param array $aPostData Post data (arrray [key]=>[value])) + * * $aRequest contains subkeys + * - function --> to extract method and generate url + * - method; one of GET|POST|PUT|DELETE + * - postdata; for POST only + + * @param array $aRequest arrayurl for Foreman API * @return array */ - public function makeRequest($url, $method='GET', $aPostData = false) { + public function makeRequest($aRequest=false) { + if ($aRequest){ + $this->_aRequest=$aRequest; + } $sStatus='unknown'; $bOk=false; - - // check name of method - if(array_search($method, array('GET', 'POST', 'PUT', 'DELETE'))===false){ - die("ERROR in ".__CLASS__."::".__FUNCTION__.": method $method is invalid or not supported."); - } + + $this->_aRequest['method']=$this->_getMethod(); // prevent missing data because of paging - if ($method==='GET'){ - $url.='?per_page=1000'; + if ($this->_aRequest['method']==='GET' && !array_key_exists('per_page', $this->_aRequest)){ + $this->_aRequest['per_page']=1000; } - if ($method==='POST' && (!$aPostData || !count($aPostData))){ + // check postdata + if ($this->_aRequest['method']==='POST' && (!array_key_exists('postdata',$this->_aRequest) || !count($this->_aRequest['postdata']))){ die("ERROR in ".__CLASS__."::".__FUNCTION__.": missing data to make a POST request"); } - $aReturn=$this->_httpCall($url, $method); + // add url parameters (search, paging) + $this->_aRequest['url']=$this->_generateUrl(); + $this->_aRequest['url']=$this->_generateParams(); - // --- check status + // ----- request + $aReturn=$this->_httpCall(); + + // ----- check result + // check status $iStatuscode=$aReturn['info']['http_code']; if ($iStatuscode===0){ $sStatus='wrong host'; @@ -142,11 +252,11 @@ class deployForeman { $sStatus='wrong url'; } - // --- check result json + // check result json if($bOk){ $aJson=json_decode($aReturn['body'], 1); if (is_array($aJson)){ - if ($aJson['total'] > $aJson['per_page']){ + if (array_key_exists('total', $aJson) && $aJson['total'] > $aJson['per_page']){ $bOk=false; $sStatus='Http OK, but incomplete results (paging)'; } @@ -162,22 +272,40 @@ class deployForeman { return $aReturn; } + // ---------------------------------------------------------------------- - // public functions + // public foreman functions // ---------------------------------------------------------------------- /** * get list of host groups as an array with [id] => [name of title] + * $aOptions ... can contain optional subkeys + * - id - id of hostgroup + * - more - url behind "id" + * - search + * - page + * - per_page + * + * @param array $aOptions * @return boolean */ - public function getHostgroups() { + public function getHostgroups($aOptions=array()) { $aReturn=array(); - $aData=$this->makeRequest('hostgroups/', 'GET'); + + $this->_aRequest=$aOptions; + $this->_aRequest['function']=__FUNCTION__; + $aData=$this->makeRequest(); if (!$aData['_OK']){ return false; } - if ($aData['_json']){ + + // TODO: call a general method to create result array ... baased on + // $aOptions['result'] ... + + if (array_key_exists('id', $aOptions)){ + $aReturn[$aData['_json']['id']]=$aData['_json']['title']; + } else if (array_key_exists('_json', $aData) && count($aData['_json'])){ foreach ($aData['_json']['results'] as $aItem){ $aReturn[$aItem['id']]=$aItem['title']; }