Skip to content
Snippets Groups Projects
Commit 13356a34 authored by Hahn Axel (hahn)'s avatar Hahn Axel (hahn)
Browse files

task 1462 - add foreman integration: first commit of foreman API class - GET to hostgroups works

parent eff250b9
Branches
No related tags found
No related merge requests found
...@@ -15,21 +15,72 @@ ...@@ -15,21 +15,72 @@
class deployForeman { class deployForeman {
protected $_aCfg=array(); protected $_aCfg=array();
protected $_bDebug = false;
/**
* alloews methods and prefixes for methods protected $_aAllowedUrls=array(
* @var array 'api/'=>array(
*/ ''=>array(),
protected $_aAllowedMethods=array( 'architectures'=>array(),
'GET'=>'get', 'audits'=>array('methods'=>array('GET')),
'POST'=>'create', 'auth_source_ldaps'=>array(),
'PUT'=>'update', 'bookmarks'=>array(),
'DELETE'=>'delete' 'common_parameters'=>array(),
'compliance'=>array(),
'compute_attributes'=>array(),
'compute_profiles'=>array(),
'compute_resources'=>array(),
'config_groups'=>array(),
'config_reports'=>array(),
'config_templates'=>array(),
'dashboard'=>array('methods'=>array('GET')),
'domains'=>array(),
'environments'=>array(),
'fact_values'=>array(),
'filters'=>array(),
'hosts'=>array(),
'hostgroups'=>array(),
'job_invocations'=>array(),
'job_templates'=>array(),
'locations'=>array(),
'mail_notifications'=>array(),
'media'=>array(),
'models'=>array(),
'operatingsystems'=>array('methods'=>array('GET')),
'orchestration'=>array(),
'organizations'=>array(),
'permissions'=>array(),
'plugins'=>array(),
'provisioning_templates'=>array(),
'ptables'=>array(),
'puppetclasses'=>array(),
'realms'=>array(),
'remote_execution_features'=>array(),
'reports'=>array(),
'roles'=>array(),
'settings'=>array(),
'smart_class_parameters'=>array(),
'smart_proxies'=>array(),
'smart_variables'=>array(),
'statistics'=>array('methods'=>array('GET')),
'status'=>array('methods'=>array('GET')),
'subnets'=>array(),
'template_combinations'=>array(),
'template_kinds'=>array('methods'=>array('GET')),
'templates'=>array(),
'usergroups'=>array(),
'users'=>array(),
// ...
),
'api/v2/'=>array(
'discovered_hosts'=>array(),
'discovery_rules'=>array(),
),
'foreman_tasks/api/'=>array(
'recurring_logics'=>array(),
'tasks'=>array(),
),
); );
protected $_aApiUrls=array(
'hostgroups'=>'hostgroups/',
);
protected $_aRequest=array(); protected $_aRequest=array();
...@@ -64,54 +115,47 @@ class deployForeman { ...@@ -64,54 +115,47 @@ class deployForeman {
} }
/** /**
* helper function ... get the METHOD by scanning function and search for * search url prefix in $this->_aAllowedUrls by given key
* it in _aAllowedMethods * @param type $sFunction
* i.e. "getHostname" --> returns GET
*
* @return type * @return type
*/ */
protected function _getMethod(){ protected function _guessPrefixUrl($sFunction=false){
$sReturn=''; $sReturn='';
foreach ($this->_aAllowedMethods as $sMethod=>$sPrefix){ if (!$sFunction){
if (strpos($this->_aRequest['function'], $sPrefix)===0){ $sFunction=$this->_aRequest['request'][0][0];
$sReturn=$sMethod; }
continue; foreach($this->_aAllowedUrls as $sPrefix=>$aUrls){
foreach(array_keys($aUrls) as $sKeyword){
if ($sFunction==$sKeyword){
$sReturn=$sPrefix;
break;
} }
} }
if (!$sReturn){
die("ERROR in ".__CLASS__."::".__FUNCTION__.": function ".$this->_aRequest['function']." does not map to a valid method.");
} }
return $sReturn; return $sReturn;
} }
/** /**
* generate an url for foreman API request based on option keys * 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 * @return string
*/ */
protected function _generateUrl(){ protected function _generateUrl(){
$sFunction=strtolower($this->_aRequest['function']); if(!array_key_exists('request', $this->_aRequest)){
foreach (array_values($this->_aAllowedMethods) as $sMethod){ die('ERROR: missing key [request]');
$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]; $sReturn=$this->_aCfg['api'];
$sPrefix=$this->_guessPrefixUrl();
$sReturn.=$sPrefix;
if (array_key_exists('id', $this->_aRequest)){ foreach($this->_aRequest['request'] as $aReqItem){
$sReturn.=(int)$aOptions['id'].'/'; if (!array_key_exists($aReqItem[0], $this->_aAllowedUrls[$sPrefix])){
echo 'WARNING: wrong item: [' . $aReqItem[0]."]<br>\n";
}
$sReturn.=$aReqItem[0] ? $aReqItem[0].'/' : '';
if(count($aReqItem)>1){
$sReturn.=(int)$aReqItem[1].'/';
} }
if (array_key_exists('more', $this->_aRequest)){
$sReturn.=$aOptions['more'].'/';
} }
return $sReturn; return $sReturn;
} }
...@@ -122,13 +166,15 @@ class deployForeman { ...@@ -122,13 +166,15 @@ class deployForeman {
* @return string * @return string
*/ */
protected function _generateParams(){ protected function _generateParams(){
$sUrl=$this->_aRequest['url']; if (!array_key_exists('filter', $this->_aRequest)){
$sReturn=$sUrl.(strpos($sUrl, '?') ? '' : '?'); return '';
}
$sReturn='?';
// TODO: "sort by" and "sort order" ... need to be added here ... somehow // TODO: "sort by" and "sort order" ... need to be added here ... somehow
foreach(array('page', 'per_page', 'search') as $sParam){ foreach(array('page', 'per_page', 'search') as $sParam){
if (array_key_exists($sParam, $this->_aRequest)){ if (array_key_exists($sParam, $this->_aRequest['filter'])){
$sReturn.='&'.$sParam.'='.urlencode($this->_aRequest[$sParam]); $sReturn.='&'.$sParam.'='.urlencode($this->_aRequest['filter'][$sParam]);
} }
} }
return $sReturn; return $sReturn;
...@@ -148,19 +194,17 @@ class deployForeman { ...@@ -148,19 +194,17 @@ class deployForeman {
if ($aRequest){ if ($aRequest){
$this->_aRequest=$aRequest; $this->_aRequest=$aRequest;
} }
// $url, $method='GET', $aPostData = false, $iTimeout = 5
$this->log(__FUNCTION__ . " start <pre>".print_r($this->_aRequest,1)."</pre>"); $this->log(__FUNCTION__ . " start <pre>".print_r($this->_aRequest,1)."</pre>");
if (!function_exists("curl_init")) { if (!function_exists("curl_init")) {
die("ERROR: PHP CURL module is not installed."); die("ERROR: PHP CURL module is not installed.");
} }
$sApiUrl=$this->_aCfg['api'];
$sApiUser=array_key_exists('user', $this->_aCfg) ? $this->_aCfg['user'] : false; $sApiUser=array_key_exists('user', $this->_aCfg) ? $this->_aCfg['user'] : false;
$sApiPassword=array_key_exists('password', $this->_aCfg) ? $this->_aCfg['password'] : false; $sApiPassword=array_key_exists('password', $this->_aCfg) ? $this->_aCfg['password'] : false;
$sFullUrl=$sApiUrl.$this->_aRequest['url']; $sFullUrl=$sApiUrl.$this->_aRequest['url'];
$this->log(__FUNCTION__ . " ".$this->_aRequest['method']." $sFullUrl"); $this->log(__FUNCTION__ . " ".$this->_aRequest['method']." " . $this->_aRequest['url']);
$ch = curl_init($sFullUrl); $ch = curl_init($this->_aRequest['url']);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->_aRequest['method']); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->_aRequest['method']);
if ($this->_aRequest['method']==='POST'){ if ($this->_aRequest['method']==='POST'){
...@@ -187,6 +231,18 @@ class deployForeman { ...@@ -187,6 +231,18 @@ class deployForeman {
return $aReturn; return $aReturn;
} }
/**
* write debug infos if enabled
* @param string $sMessage
* @return boolean
*/
protected function _writeDebug($sMessage){
if ($this->_bDebug){
echo "$sMessage<br>\n";
}
return true;
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// public functions :: low level // public functions :: low level
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
...@@ -217,22 +273,20 @@ class deployForeman { ...@@ -217,22 +273,20 @@ class deployForeman {
$sStatus='unknown'; $sStatus='unknown';
$bOk=false; $bOk=false;
$this->_aRequest['method']=$this->_getMethod();
// prevent missing data because of paging // prevent missing data because of paging
if ($this->_aRequest['method']==='GET' && !array_key_exists('per_page', $this->_aRequest)){ if ($this->_aRequest['method']==='GET' && !array_key_exists('per_page', $this->_aRequest['filter'])){
$this->_aRequest['per_page']=1000; $this->_aRequest['filter']['per_page']=1000;
} }
// check postdata // TODO check postdata
if ($this->_aRequest['method']==='POST' && (!array_key_exists('postdata',$this->_aRequest) || !count($this->_aRequest['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"); die("ERROR in ".__CLASS__."::".__FUNCTION__.": missing data to make a POST request");
} }
// add url parameters (search, paging) $this->_aRequest['url']=$this->_generateUrl().$this->_generateParams();
$this->_aRequest['url']=$this->_generateUrl();
$this->_aRequest['url']=$this->_generateParams();
// ----- request // ----- request
$this->_writeDebug(__FUNCTION__ . ' start request <pre>'.print_r($this->_aRequest,1).'</pre>');
$aReturn=$this->_httpCall(); $aReturn=$this->_httpCall();
// ----- check result // ----- check result
...@@ -268,49 +322,137 @@ class deployForeman { ...@@ -268,49 +322,137 @@ class deployForeman {
} }
$aReturn['_OK']=$bOk; $aReturn['_OK']=$bOk;
$aReturn['_status']=$sStatus; $aReturn['_status']=$sStatus;
$this->_writeDebug(__FUNCTION__ . ' result of request <pre>'.print_r($aReturn,1).'</pre>');
return $aReturn; return $aReturn;
} }
/**
* filter output for the response based on values $this->_aRequest['response']
* @param array $aData response of $this->makeRequest();
* @return array
*/
protected function _filterOutput($aData){
if(!array_key_exists('response', $this->_aRequest)){
return $aData;
}
$aTmp=array_key_exists('results', $aData['_json']) ? $aData['_json']['results'] : array($aData['_json']);
if(!count($aTmp)){
return array();
}
$aReturn=array();
foreach($aTmp as $aItem){
$aReturn[] = array_filter($aItem, function($key) {
return array_search($key, $this->_aRequest['response']) !==false;
}, ARRAY_FILTER_USE_KEY
);
}
return $aReturn;
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// public foreman functions // public foreman functions
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
/** /**
* get list of host groups as an array with [id] => [name of title] * enable/ disable debugging
* @param boolean $bNewDebugFlag new value; true|false
* @return boolean
*/
public function setDebug($bNewDebugFlag){
return $this->_bDebug=$bNewDebugFlag;
}
/**
* check for missing config entries
* @return type
*/
public function selfcheck() {
$sOut='';
$sWarning='';
$sOut.="<h1>selfcheck</h1>";
$aApi=$this->read(array('request'=>array(array(''))));
if($aApi['_OK']){
foreach($aApi['_json']['links'] as $sKey=>$aCalls){
$sOut.="<h2>$sKey</h2><ul>";
foreach ($aCalls as $sLabel=>$sUrl){
$sOut.="<li>$sLabel .. $sUrl ";
$aTmp=preg_split('#\/#', $sUrl);
$sDir2=count($aTmp)>2 ? $aTmp[2] : '??';
$sDir3=count($aTmp)>3 ? $aTmp[3] : '??';
$sOut.="..... "
. ($this->_guessPrefixUrl($sDir2).$this->_guessPrefixUrl($sDir3)
?'<span style="background:#cfc">OK</span>'
:'<span style="background:#fcc">miss</span>'
) . ' ' . $sDir2.', '.$sDir3 . "</li>\n";
if (!($this->_guessPrefixUrl($sDir2).$this->_guessPrefixUrl($sDir3))){
$sWarning.="<li>$sKey - $sLabel - $sUrl</li>";
}
}
$sOut.="</ul>";
}
} else {
$sOut.='ERROR: connect to foreman failed.<br>';
}
if ($sWarning){
echo 'WARNINGS:<ol>'.$sWarning.'</ol>';
}
echo $sOut;
echo 'API: <pre>'.print_r($aApi,1).'</pre>';
return true;
}
// ----------------------------------------------------------------------
// public foreman API functions
// ----------------------------------------------------------------------
/**
* TODO: create
* @param array $aOptions
*/
public function create($aOptions){
}
/**
* GETTER
* $aOptions ... can contain optional subkeys * $aOptions ... can contain optional subkeys
* - id - id of hostgroup * - request
* - more - url behind "id" * [] list of array(keyword [,id])
* - search * - filter (array)
* - page * - search (string)
* - per_page * - page (string)
* - per_page (string)
* - response (array)
* - list of keys, i.e. array('id', 'title')
* *
* @param array $aOptions * @param array $aOptions
* @return boolean * @return array
*/ */
public function getHostgroups($aOptions=array()) { public function read($aOptions){
$aReturn=array();
$this->_aRequest=$aOptions; $this->_aRequest=$aOptions;
$this->_aRequest['function']=__FUNCTION__; $this->_aRequest['method']='GET';
$aData=$this->makeRequest(); $aData=$this->makeRequest();
if (!$aData['_OK']){ if (!$aData['_OK']){
return false; return false;
} }
return $this->_filterOutput($aData);
}
// TODO: call a general method to create result array ... baased on /**
// $aOptions['result'] ... * TODO
* @param type $aOptions
*/
public function update($aOptions){
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'];
}
} }
return $aReturn;
/**
* TODO
* @param type $aOptions
*/
public function delete($aOptions){
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment