Skip to content
Snippets Groups Projects
Select Git revision
  • 12867b6d212fb92feb43e5a8f87968edfd9c1ec7
  • master default protected
  • simple-task/7248-eol-check-add-node-22
  • 6877_check_iml_deployment
4 results

check_disk-io

Blame
  • foremanapi.class.php 19.91 KiB
    <?php
    /**
     * ForemanApi
     * 
     * foreman access to API
     * 
     * @example
     * in project class
     * $oForeman=new ForemanApi($this->_aConfig['foreman']);
     * 
     * // enable debugging
     * $oForeman->setDebug(1);
     * 
     * // self check
     * $oForeman->selfcheck(); die(__FUNCTION__);
     *
     * // read operating systems and get id and title only
     * $aForemanHostgroups=$oForeman->read(array(
     *    'request'=>array(
     *        array('operatingsystems'),
     *    ),
     *    'response'=>array(
     *        'id','title'
     *   ),
     * ));
     * 
     * // read details for operating systems #4
     * $aForemanHostgroups=$oForeman->read(array(
     *    'request'=>array(
     *        array('operatingsystems', 4),
     *    ),
     * ));
     *
     * 
     * $aOptions ... can contain optional subkeys
     * - request
     *      [] list of array(keyword [,id])
     * - filter (array)
     *      - search (string)
     *      - page (string)
     *      - per_page (string)
     * - response (array)
     *      - list of keys, i.e. array('id', 'title')
    
     * @author hahn
     */
    class ForemanApi {
    
        protected $_aCfg=array();
        protected $_bDebug = false;
    
        protected $_aAllowedUrls=array(
            'api'=>array(
                ''=>array(),
                'architectures'=>array(),
                'audits'=>array('methods'=>array('GET')),
                'auth_source_ldaps'=>array(),
                'bookmarks'=>array(),
                '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(),
            ),
        );
        
        
        /**
         * last request
         * @var type 
         */
        protected $_aRequest=array();
        
        /**
         * last response
         * @var type 
         */
        protected $_aResponse=array();
        
        
        // ----------------------------------------------------------------------
        // constructor
        // ----------------------------------------------------------------------
        
        
        public function __construct($aCfg) {
            if(!isset($aCfg['api'])){
                die("ERROR: class ".__CLASS__." must be initialized with an array containing api config for foreman.");
                return false;
            }
            $this->_aCfg=$aCfg;
            
            return true;
        }
        
        // ----------------------------------------------------------------------
        // private functions
        // ----------------------------------------------------------------------
        /**
         * add a log messsage
         * @global object $oLog
         * @param  string $sMessage  messeage text
         * @param  string $sLevel    warnlevel of the given message
         * @return bool
         */
        protected function log($sMessage, $sLevel = "info") {
            global $oCLog;
            return $oCLog->add(basename(__FILE__) . " class " . __CLASS__ . " - " . $sMessage, $sLevel);
        }
        
        /**
         * search url prefix in $this->_aAllowedUrls by given key
         * @param type $sFunction
         * @return type
         */
        protected function _guessPrefixUrl($sFunction=false){
            $sReturn='';
            /*
            if (!$sFunction){
                $sFunction=$this->_aRequest['request'][0][0];
            }
             * 
             */
            foreach($this->_aAllowedUrls as $sPrefix=>$aUrls){
                foreach(array_keys($aUrls) as $sKeyword){
                    if ($sFunction==$sKeyword){
                        $sReturn=$sPrefix;
                        break;
                    }
                }
            }
            return $sReturn;
        }
    
        /**
         * generate an url for foreman API request based on option keys
         * @return string
         */
        protected function _generateUrl(){
            if(!isset($this->_aRequest['request'])){
                die('ERROR: missing key [request]');
            }
            $sReturn=$this->_aCfg['api'];
            
            $sPrefix=$this->_guessPrefixUrl();
            $sReturn.=$sPrefix.'/';
            
            foreach($this->_aRequest['request'] as $aReqItem){
                if (!isset($this->_aAllowedUrls[$sPrefix][$aReqItem[0]])){
                    echo 'WARNING: wrong item: [' . $aReqItem[0]."]<br>\n";
                }
                $sReturn.=$aReqItem[0] ? $aReqItem[0].'/' : '';
                if(count($aReqItem)>1){
                    $sReturn.=(int)$aReqItem[1].'/';
                }
            }
            return $sReturn;
        }
        
        /**
         * add parameter for search and paging in an foreman API URL
         * 
         * @return string
         */
        protected function _generateParams(){
            if (!isset($this->_aRequest['filter'])){
                return '';
            }
            $sReturn='?';
            
            foreach ($this->_aRequest['filter'] as $sKey=>$value){
                $sReturn.='&'.$sKey.'='.urlencode($value);
            }
            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 = 15) {
            if ($aRequest){
                $this->_aRequest=$aRequest;
            }
            $this->_aResponse=array();
            $this->log(__FUNCTION__ . " start <pre>".print_r($this->_aRequest,1)."</pre>");
            if (!function_exists("curl_init")) {
                die("ERROR: PHP CURL module is not installed.");
            }
            
            $sApiUser=isset($this->_aCfg['user']) ? $this->_aCfg['user'] : false;
            $sApiPassword=isset($this->_aCfg['password']) ? $this->_aCfg['password'] : false;
    
            // $sFullUrl=$sApiUrl.$this->_aRequest['url'];
            $sFullUrl=$this->_aRequest['url'];
            $this->log(__FUNCTION__ . " ".$this->_aRequest['method']." " . $this->_aRequest['url']);
            $ch = curl_init($this->_aRequest['url']);
    
            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);
            
            if (array_key_exists('ignore-ssl-error', $this->_aCfg) && $this->_aCfg['ignore-ssl-error']){
                $this->log(__FUNCTION__ . " WARNING: SSL errors will be ignored by config.", 'warning');
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
            }
            curl_setopt($ch, CURLOPT_TIMEOUT, $iTimeout);
            curl_setopt($ch, CURLOPT_USERAGENT, 'IML Deployment GUI :: ' . __CLASS__);
            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__ . " status ".$aReturn['info']['http_code'].' '.$this->_aRequest['method']." $sFullUrl");
            $sHeader=substr($res, 0, $aReturn['info']['header_size']);
            $aReturn['header']=explode("\n", $sHeader);
            $aReturn['body']=str_replace($sHeader, "", $res);
    
            return $aReturn;
        }
    
        /**
         * write debug infos if enabled
         * @param string $sMessage
         * @return boolean
         */
        protected function _writeDebug($sMessage){
            if ($this->_bDebug){
                echo "DEBUG :: ".__CLASS__." :: $sMessage<br>\n";
            }
            return true;
        }
    
        // ----------------------------------------------------------------------
        // public functions :: low level
        // ----------------------------------------------------------------------
        
        /**
         * make an http(s) request to foreman and scan result for http code and
         * content in response json; method returns an array with subkeys
         * - info: curl info array
         * - error: curl error message
         * - header: http response headers
         * - body: http response body
         * - _json: parsed json data from response body
         * - _OK: flag if result is OK and complete
         * - _status: info
         * 
         *      * $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($aRequest=false) {
            if ($aRequest){
                $this->_aRequest=$aRequest;
            }
            $sStatus='unknown';
            $bOk=false;
            
            
            // prevent missing data because of paging
            if ($this->_aRequest['method']==='GET' && !isset($this->_aRequest['filter']['per_page'])){
                $this->_aRequest['filter']['per_page']=1000;
            }
            // TODO check postdata
            if ($this->_aRequest['method']==='POST' && (
                    !isset($this->_aRequest['postdata']) 
                    || !is_array($this->_aRequest['postdata']) 
                    || !count($this->_aRequest['postdata'])
                )
            ){
                die("ERROR in ".__CLASS__."::".__FUNCTION__.": missing data to make a POST request");
            }
            
            $this->_aRequest['url']=isset($this->_aRequest['url']) 
                ? $this->_aRequest['url']
                : $this->_generateUrl().$this->_generateParams()
            ;
    
            // ----- request
            $this->_writeDebug(__FUNCTION__ . ' start request <pre>'.print_r($this->_aRequest,1).'</pre>');
            $aReturn=$this->_httpCall();
            
            // ----- check result
            // check status
            $iStatuscode=$aReturn['info']['http_code'];
            if ($iStatuscode===0){
                $sStatus='wrong host or no connect';
            }
            if ($iStatuscode>=200 && $iStatuscode<400){
                $sStatus='OK';
                $bOk=true;
            }
            if ($iStatuscode>=400 && $iStatuscode<500){
                $sStatus='error';
            }
            if ($iStatuscode===404){
                $sStatus='wrong url';
            }
            
            // check result json
            if($bOk){
                $aJson=json_decode($aReturn['body'], 1);
                if (is_array($aJson)){
                    if (isset($aJson['total']) && $aJson['total'] > $aJson['per_page']){
                        $bOk=false;
                        $sStatus='Http OK, but incomplete results (paging)';
                    }
                    $aReturn['_json']=$aJson;
                } else {
                    $bOk=false;
                    $sStatus='Http OK, but wrong response';
                }
            }
            $aReturn['_OK']=$bOk;
            $aReturn['_status']=$sStatus;
            $this->_writeDebug(__FUNCTION__ . ' result of request <pre>'.print_r($aReturn,1).'</pre>');
            $this->_aResponse=$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(!isset($this->_aRequest['response'])){
                return $aData;
            }
            $aTmp=isset($aData['_json']['results']) ? $aData['_json']['results'] : array($aData['_json']);
            if(!count($aTmp)){
                return array();
            }
            $aReturn=array();
            foreach($aTmp as $aItem){
                $aReturnitem=array();
                foreach($this->_aRequest['response'] as $sKey){
                    if (array_key_exists($sKey, $aItem)){
                        $aReturnitem[$sKey]=$aItem[$sKey];
                    }
                }
                $aReturn[] = $aReturnitem;
            }
            /*
            return ($bIsList==1)
                    ? $aReturn 
                    : (count($aReturn) ? $aReturn[0] : array());
            */
            return $aReturn;
        }
    
    
        // ----------------------------------------------------------------------
        // public foreman functions
        // ----------------------------------------------------------------------
    
        /**
         * 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: unable to connect to foreman or missing permissions.<br>';
            }
            if ($sWarning){
                echo 'WARNINGS:<ol>'.$sWarning.'</ol>';
            }
            echo $sOut;
            return true;
        }
        
        // ----------------------------------------------------------------------
        // public foreman API CRUD functions
        // ----------------------------------------------------------------------
        
        /**
         * TODO: create
         * @param array $aOptions
         */
        public function create($aOptions){
            /*
            $this->_aRequest=$aOptions;
            $this->_aRequest['method']='POST';
            return $this->makeRequest();
             */
        }
        /**
         * GETTER
         * $aOptions ... can contain optional subkeys
         * - request
         *      [] list of array(keyword [,id])
         * - filter (array)
         *      - search (string)
         *      - page (string)
         *      - per_page (string)
         *      - any attribute in the return resultset
         * - response (array)
         *      - list of keys, i.e. array('id', 'title')
         * 
         * @param array  $aOptions  
         * @return array
         */
        public function read($aOptions){
            $this->_aRequest=$aOptions;
            $this->_aRequest['method']='GET';
            $aData=$this->makeRequest();
            if (!$aData['_OK']){
                return false;
            }
            return $this->_filterOutput($aData);
        }
        
        /**
         * TODO
         * @param type $aOptions
         */
        public function update($aOptions){
            /*
            $this->_aRequest=$aOptions;
            $this->_aRequest['method']='PUT';
            return $this->makeRequest();
             */
        }
        
        /**
         * TODO
         * @param type $aOptions
         */
        public function delete($aOptions){
            /*
            $this->_aRequest=$aOptions;
            $this->_aRequest['method']='DELETE';
            return $this->makeRequest();
             */
        }
    
        // ----------------------------------------------------------------------
        // get response infos 
        // ----------------------------------------------------------------------
        
        /**
         * get curl info data from last response
         * Array
            (
                [url] => https://foreman/api/hostgroups/?&per_page=1000
                [content_type] => application/json; charset=utf-8
                [http_code] => 200
                [header_size] => 1034
                [request_size] => 218
                [filetime] => -1
                [ssl_verify_result] => 0
                [redirect_count] => 0
                [total_time] => 1.644417
                [namelookup_time] => 0.007198
                [connect_time] => 0.009012
                [pretransfer_time] => 0.0332
                [size_upload] => 0
                [size_download] => 119602
                [speed_download] => 72732
                [speed_upload] => 0
                [download_content_length] => -1
                [upload_content_length] => 0
                [starttransfer_time] => 1.642775
                [redirect_time] => 0
                [redirect_url] => 
                [primary_ip] => 10.0.2.10
                [certinfo] => Array
                    (
                    )
    
                [primary_port] => 443
                [local_ip] => 10.0.2.15
                [local_port] => 33906
            )
         * @param string $sKey  get value of given key only
         * @return any
         */
        public function getResponseInfo($sKey=false){
            
            if($sKey){
                return isset($this->_aResponse['info'][$sKey]) 
                    ? $this->_aResponse['info'][$sKey] 
                    : false
                ;
            }
            return isset($this->_aResponse['info']) 
                    ? $this->_aResponse['info']
                    : false
                ;
            /*
            return isset($sKey) && $sKey
                ? isset($this->_aResponse['info'][$sKey]) 
                    ? $this->_aResponse['info'][$sKey] 
                    : false
                : isset($this->_aResponse['info']) 
                    ? $this->_aResponse['info']
                    : false
            ;
             */
        }
        
        /**
         * get array of last http response header
         * @return array
         */
        public function getResponseHeader(){
            return isset($this->_aResponse['header']) 
                    ? $this->_aResponse['header']
                    : false
                ;
        }
        /**
         * get status of last request
         * @return string
         */
        public function getResponseStatus(){
            // print_r($this->_aResponse); die();
            return isset($this->_aResponse['_status']) 
                    ? $this->_aResponse['_status']
                    : false
                ;
        }
    }