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

check_cpu

Blame
  • rollout_base.class.php 23.96 KiB
    <?php
    require_once 'rollout.interface.php';
    require_once 'cache.class.php';
    
    /**
     * rollout_base class that will be extended in a rollout plugin
     * see deployment/plugins/rollout/*
     * 
     * @author axel
     */
    class rollout_base implements iRolloutplugin{
        
        // ---------------------------------------------------------------
        // VARIABLES
        // ---------------------------------------------------------------
        /**
         * identifier for current plugin; it us used to find the current plugin
         * settings in the config structore for global and project based config
         * @var string
         */
        protected $_sPluginId='UNSET';
        /**
         * data with plugin infos (read from info.json)
         * @var array
         */
        protected $_aPlugininfos=false;
        
        /**
         * array with translation texts
         * @var type
         */
        protected $_aLang=false;
    
        /**
         * set language; 2 letter code, i.e. "de"; default language is "en" ; a 
         * file "lang_en.json" is required in the plugin dir
         * @var string
         */
        protected $_sFallbackLang = 'en-en';
    
        /**
         * set language; 2 letter code, i.e. "de"; default language is "en" ; a 
         * file "lang_en.json" is required in the plugin dir
         * @var string
         */
        protected $_sLang = 'en-en';
        
        /**
         * string with phase of project; one of preview|stage|live
         * @var type
         */
        protected $_sPhase = false;
        
        /**
         * global configuration of the rollout plugin
         * @var array
         */
        protected $_aCfgGlobal = false;
        /**
         * configuration of the project
         * @var array
         */
        protected $_aCfgProject = false;
        
        protected $_sNamePrefix4Project=false; // set in constructor
        protected $_sNamePrefix4Phase=false; // set in constructor
        
        // ---------------------------------------------------------------
        // CONSTRUCTOR
        // ---------------------------------------------------------------
    
        /**
         * initialize rollout plugin
         * @param array $aParams  hash with those possible keys
         *                  lang         string   language, i.e. 'de'
         *                  phase        string   name of phase in a project
         *                  globalcfg    array    given global config $aConfig
         *                  projectcfg   array    project config to generate config 
         *                                        for project and all phases
         * @return boolean
         */
        public function __construct($aParams) {
            
            // set current plugin id - taken from plugin directory name above
            $oReflection=new ReflectionClass($this);
            $this->_sPluginId=basename(dirname($oReflection->getFileName()));
       
            // ----- init language
            if (isset($aParams['lang'])){
                $this->setLang($aParams['lang']);
            } else {
                $this->setLang();
            }
            
            // ----- init phase
            if (isset($aParams['phase'])){
                $this->setPhase($aParams['phase']);
            }
    
            // ----- init global config
            if (isset($aParams['globalcfg'])){
                $this->setGlobalConfig($aParams['globalcfg']);
            }
            // ----- init project config
            if (isset($aParams['projectcfg'])){
                $this->setProjectConfig($aParams['projectcfg']);
            }
            return true;
        }
        
        // ---------------------------------------------------------------
        // FORM HELPER
        // ---------------------------------------------------------------
    
        /**
         * get a string for a prefix for name attribute in form vars. 
         * It is important to store the value in the wanted structure.
         * 
         * @param type $sPhase
         * @return type
         */
        protected function _getNamePrefix($sPhase=false){
            return ($sPhase
                ? 'phases['.$sPhase.'][plugins][rollout]['.$this->getId().']'
                : 'plugins[rollout]['.$this->getId().']'
            );
        }
        
        /**
         * get Data from a callback function and store it in a cache
         * The response type depends on the callback function
         * 
         * @param string   $sFunctionname  name of the callback function
         * @param string   $sKey           name of the key; "project" or name of phase
         * @param integr   $iTtl           ttl value = how many seconds to use cache
         * @param integr   $iTtlOnError    ttl value = how many seconds to use cache if there was no response
         * @return type
         */
        protected function _getCallback($sFunctionname, $sKey, $iTtl=15,$iTtlOnError=10){
            $oCache=new AhCache('rollout-'.$this->getId(), 'callback-'.$sFunctionname.'-'.$sKey);
            if($oCache->isExpired()){
                $aMydata= call_user_func(array($this, $sFunctionname));
                // echo "$sFunctionname fresh ".($aMydata ? "OK": "false")." - storing for $iTtl sec<br>";
                $oCache->write($aMydata, ($aMydata ? $iTtl : $iTtlOnError));
            } else {
                // echo "$sFunctionname from cache ... ".$oCache->iExpired()." sec <br>";
                $aMydata=$oCache->read();
            }
            // echo '<pre>'.print_r($aMydata, 1).'</pre>'; die(__METHOD__);
            return $aMydata;
        }
        /**
         * render a form by given form elementes 
         * @param  array   $aFormdata  array of form elements
         * @param  string  $sKey       part of the identifier used in id of the input field
         * @return string
         */
        protected function _renderForm($aFormdata, $sKey){
            static $i;
            if (!isset($i)){
                $i=0;
            }
    
            $sReturn='';
            $sKeyPrefix=$this->getId().'_'.$sKey;
            
            $oForm = new formgen();
            foreach ($aFormdata as $elementData) {
                $elementKey=$sKeyPrefix.'_'.$i++;
                $sReturn.=$oForm->renderHtmlElement($elementKey, $elementData);
            }
            return $sReturn;
        }
        
        /**
         * render form fields for global plugin variables
         * @param string  $sScope       scope of vars ... one of global|project|phase
         * @param string  $sPhase       optional: render global vars in a phase; if no phase was set it renders form fields for project based settings
         * @return string
         */
        protected function _renderForm4Vars($sScope, $sPhase=false){
            $sReturn='';
            
            // test vars from info.json file
            $aInfos=$this->getPluginInfos();
            if(!isset($aInfos['vars'][$sScope]) || !count($aInfos['vars'][$sScope])){
                return '';
            }
            
            $sKey=($sPhase ? 'phase_'.$sPhase : 'project');
            $sPrefixName=$this->_getNamePrefix($sPhase);
            
            // set defaults - to be used in placeholder attribute
            // no phase = project level - take global defaults of ci config
            // on a phase - fetch merged cofig data of project
            $aDefaultValues=($sPhase ? $this->getConfig() : $this->_aCfgGlobal);
            $aDefaultSource=($sPhase ? 'project' : 'global');
                    
            // set defaults - to be used in value attribute
            $aValues=($sPhase 
                    ? $this->_aCfgProject['phases'][$sPhase]['plugins']['rollout'][$this->getId()] 
                    : $this->_aCfgProject['plugins']['rollout'][$this->getId()]
            );
            
     
            // create form fields
            // $aFormdata[]=array('type' => 'markup','value' => '<br>'.$this->_t('section-override-'.$sScope.'-vars').':');
            $aFormdata[]=array('type' => 'markup','value' => '<div style="style: clear: left;"></div><h4>'.$this->getId() .' :: '. $sScope.'</h4>');
            
            $sMiss='';
            foreach ($aInfos['vars'][$sScope] as $sVarname=>$aVarinfos){
                if ($sScope==='global' && !isset($this->_aCfgGlobal[$sVarname])){
                    $sMiss.='- plugin var was not set in global CI config: "'.$sVarname.'".<br>';
                }
                
                
                $sMyPlaceholder=(isset($aDefaultValues[$sVarname]) 
                                    ? htmlentities($aDefaultValues[$sVarname]) 
                                    : (isset($aVarinfos['default']) ? $aVarinfos['default'] : 'N.A.')
                    );
                
                // if a callback was set for this variable
                if(isset($aVarinfos['callback'])){
                    $aCallbackData=$this->_getCallback(
                            $aVarinfos['callback'], 
                            (isset($aVarinfos['per_scope']) && $aVarinfos['per_scope'] ? $sKey : ''), 
                            (isset($aVarinfos['ttl']) ? $aVarinfos['ttl'] : 60)
                    );
                    if(!$aCallbackData){
                        $aVarinfos['type']='text';
                    } else {
                        $aEffectiveConfig=$this->getConfig($sPhase);
                        // echo $sKey.' ... '; print_r($aEffectiveConfig[$sVarname]); echo '<br>';
                        
                        // mark entry as active ... for select and radio
                        if(isset($aEffectiveConfig[$sVarname]) && isset($aCallbackData[$aEffectiveConfig[$sVarname]])){
                            $aCallbackData[$aEffectiveConfig[$sVarname]]['selected']='selected';
                            $aCallbackData[$aEffectiveConfig[$sVarname]]['checked']='checked';
                            $aCallbackData[$aEffectiveConfig[$sVarname]]['label'].=' &laquo;&laquo;';
                        } elseif ($aVarinfos['type']==='select') {
                            $aCallbackData=array_merge(array('NO_SELECTED_ITEM_YET'=>array('value'=>'', 'label'=>'...')), $aCallbackData);
                        }
     
                        // wenn value = defaultvalue, dann value auf '' setzen (damit bei Default vom Scope
                        // davor ein Leerstring übergeben wird - analog onfocusout im Text Input
                        if (isset($aCallbackData[$aDefaultValues[$sVarname]])){
                            $aCallbackData[$aDefaultValues[$sVarname]]['value']='';
                            $aCallbackData[$aDefaultValues[$sVarname]]['label'].=' (*)';
                        } 
                        // print_r($aCallbackData[$sVarname]); echo "<br>";
                    }
                    // echo '<pre>'.$sCallbackfunktion .' = '. print_r($aMydata,1 ).'</pre>';
                }
                switch ($aVarinfos['type']) {
                    case "password":
                        $sMyPlaceholder=(isset($aDefaultValues[$sVarname]) 
                                            ? '******************************'
                                            : $sMyPlaceholder
                            );
                        $aFormdata[]=array(
                            'type' => $aVarinfos['type'],
                            'name' => $sPrefixName.'['.$sVarname.']',
                            'label' => $this->_t($sVarname.'-label'),
                            'title' => $this->_t($sVarname.'-hint'),
                            'value' => (isset($aValues[$sVarname]) ? htmlentities($aValues[$sVarname]) : ''),
                            // 'required' => 'required',
                            'validate' => 'isastring',
                            // 'size' => 25,
                            'placeholder' => $sMyPlaceholder,
                            'autocomplete' => 'off',
                        );
                        break;
                    case "select":
                    case "radio":
                        $aOptions=$aCallbackData;
                        $aFormdata[]=array(
                            'type' => $aVarinfos['type'],
                            'name' => $sPrefixName.'['.$sVarname.']',
                            'label' => $this->_t($sVarname.'-label'),
                            'title' => $this->_t($sVarname.'-hint'),
    
                            'validate' => 'isastring',
                            'options' => $aOptions,
                            
                            // 'placeholder' => $sMyPlaceholder       
                        );
                        break;
                    case "text":
                        $aFormdata[]=array(
                            'type' => $aVarinfos['type'],
                            'name' => $sPrefixName.'['.$sVarname.']',
                            'label' => $this->_t($sVarname.'-label'),
                            'ondblclick' => ($aDefaultValues[$sVarname] ? 'if (this.value==\'\') { this.value=\''.$aDefaultValues[$sVarname].'\' }' : ''),
                            'onfocusout' => ($aDefaultValues[$sVarname] ? 'if (this.value==\''.$aDefaultValues[$sVarname].'\') { this.value=\'\' }' : ''),
                            'title' => htmlentities($this->_t($sVarname.'-hint')."\n"
                                . ($this->_aCfgGlobal[$sVarname] ? '- global: '.$this->_aCfgGlobal[$sVarname]."\n" : '')
                                . ($this->_aCfgProject['plugins']['rollout'][$this->getId()][$sVarname] ? '- project: '.$this->_aCfgProject['plugins']['rollout'][$this->getId()][$sVarname]."\n" : '')
                                )
                                ,
                            'value' => (isset($aValues[$sVarname]) ? htmlentities($aValues[$sVarname]) : ''),
                            // 'required' => 'required',
                            'validate' => 'isastring',
                            // 'size' => 25,
                            'placeholder' => $sMyPlaceholder,
                            'autocomplete' => 'off',
                        );
                        break;
    
                    default:
                       $sMiss.='- plugin var "'.$sVarname.'" was not rendered - its type "'.$aVarinfos['type'].'" is not supported in the general form renderer.<br>';
                       break;
                }
            }
            // $aFormdata[]=array('type' => 'markup','value' => '<div style="style: clear: left;"></div><br><br>');
            return $this->_renderForm($aFormdata, $sKey)
                . ($sMiss 
                    ? '<pre>WARNINGS:<br>'.$sMiss.'</pre>' . ($sScope==='global' ? $this -> renderCfgExample() : '' )
                    : ''
                )
                ;
        }
        
        /**
         * get a translated text from lang_XX.json in plugin dir;
         * If the key is missed it returns "[KEY :: LANG]"
         * 
         * @see setLang()
         * @param string $sKey  key to find in lang file
         * @return string
         */
        protected function _t($sKey){
            return (isset($this->_aLang[$sKey]) && $this->_aLang[$sKey])
                    ? $this->_aLang[$sKey]
                    : "[ $sKey :: $this->_sLang ]"
            ;
        }
    
        // ---------------------------------------------------------------
        // PUBLIC METHODS
        // ---------------------------------------------------------------
    
        /**
         * set language for output of formdata and other texts.
         * This method loads the language file into a hash. The output of 
         * translated texts can be done with $this->_t("your_key")
         * 
         * @see _t()
         * @param string   $sLang  language code, i.e. "de-de"
         * @return boolean
         */
        public function setLang($sLang=false){
            $this->_sLang=$sLang ? $sLang : $this->_sLang;
            
            $oReflection=new ReflectionClass($this);
            $sFile=dirname($oReflection->getFileName()) . '/lang_'.$this->_sLang.'.json';
            if (!file_exists($sFile)){
                $sFile=dirname($oReflection->getFileName()) . '/lang_'.$this->_sFallbackLang.'.json';
                $this->_sLang=$this->_sFallbackLang;
            }
            $this->_aLang=(file_exists($sFile)) ? json_decode(file_get_contents($sFile), 1) : $this->_aLang;
            return true;
        }
        
        /**
         * set a phase for automatic use GETTER methods
         */
        public function setPhase($sPhase){
            $this->_sPhase=$sPhase;
            return true;
        }
        
    
        // ----------------------------------------------------------------------
        // INTERFACE :: CHECKS
        // ----------------------------------------------------------------------
    
        /**
         * check requirements if the plugin could work
         */
        public function checkRequirements(){
            // no specific checks needed ... always true
            return true;
        }
    
        /**
         * check access to a deploy target
         */
        public function checkConnectionToTarget(){
            // do nothing ... always true
            return true;
        }
    
        // ----------------------------------------------------------------------
        // INTERFACE :: SETTER
        // ----------------------------------------------------------------------
    
    
        /**
         * set Config ... by given global config of the current plugin
         * @param array $aConfigArray 
         */
        public function setGlobalConfig($aConfigArray){
            return $this->_aCfgGlobal=$aConfigArray;
        }
    
    
    
        /**
         * set Config ... by given project config
         */
        public function setProjectConfig($aProjectConfigArray){
            $this->_aCfgProject=$aProjectConfigArray;
            // echo '<pre>'.print_r($aProjectConfigArray, 1).'</pre>';
            // ----- ensure that the config structure exists 
            // (it is easier fo handling in getConfig())
            if (!isset($this->_aCfgProject['plugins']['rollout'][$this->_sPluginId])){
                /*
                if (!isset($this->_aCfgProject['plugins']['rollout'])){
                    if (!isset($this->_aCfgProject['plugins'])){
                        $this->_aCfgProject['plugins']=array();
                    }
                    $this->_aCfgProject['plugins']['rollout']=array();
                }
                 * 
                 */
                $this->_aCfgProject['plugins']['rollout'][$this->_sPluginId]=array('INFO'=>'created');
            }
            
            // unset empty project values to get global values
    
            foreach ($this->_aCfgProject['plugins']['rollout'][$this->_sPluginId] as $sVarname=>$value){
                if ($value===''){
                    unset($this->_aCfgProject['plugins']['rollout'][$this->_sPluginId][$sVarname]);
                }
            }
            foreach (array_keys($this->_aCfgProject['phases']) as $sMyPhase){
                if (isset($this->_aCfgProject['phases'][$sMyPhase]['plugins']['rollout'][$this->getId()])){
                    foreach($this->_aCfgProject['phases'][$sMyPhase]['plugins']['rollout'][$this->getId()] as $sVarname=>$value){
                        if ($value===''){
                            unset($this->_aCfgProject['phases'][$sMyPhase]['plugins']['rollout'][$this->getId()][$sVarname]);
                        }
                    }
                }
            }
            // TODO: 
            return $this->_aCfgProject;
        }
        
        // ----------------------------------------------------------------------
        // INTERFACE :: GETTER
        // ----------------------------------------------------------------------
    
        /**
         * get configuration for the project .. or more specifi for a given phase
         * @param  string   $sPhase
         * @param  boolean  $bMask   Flag for public output; if true then mask your secrets
         * @return array
         */
        public function getConfig($sPhase=false, $bMask=false){
    
            $aReturn=array_merge($this->_aCfgGlobal, $this->_aCfgProject['plugins']['rollout'][$this->getId()]);
            if($sPhase && isset($this->_aCfgProject['phases'][$sPhase]['plugins']['rollout'][$this->getId()])){
                $aReturn=array_merge($aReturn, $this->_aCfgProject['phases'][$sPhase]['plugins']['rollout'][$this->getId()]);
            }
            if ($bMask && isset($aReturn['password'])){
                $aReturn['password']='**********';
            }
            return $aReturn;
            /*
            return ($sPhase && isset($this->_aCfgProject['phases'][$sPhase]['plugins']['rollout'][$this->getId()]))
                ? array_merge($this->_aCfgGlobal, $this->_aCfgProject['plugins']['rollout'][$this->getId()], $this->_aCfgProject['phases'][$sPhase]['plugins']['rollout'][$this->getId()])
                : array_merge($this->_aCfgGlobal, $this->_aCfgProject['plugins']['rollout'][$this->getId()])
            ;
            */
        }
        
        /**
         * get an array with shell commands to execute
         * @param  string   $sPhase
         * @param  boolean  $bMask   Flag for public output; if true then mask your secrets
         * @return array
         */
        public function getDeployCommands($sPhase, $bMask=false){
            return [
                'echo "ERROR: The method getDeployCommamds($sPhase) was not implemented in the rollout plugin ['.$this->getId().']"',
                'exit 1'
                ];
        }
        
        /**
         * get string with current ID
         * @return string
         */
        public function getId(){
            return $this->_sPluginId;
        }
        
        /**
         * get string with plugin name (taken from plugin language file)
         * @return string
         */
        public function getName(){
            return $this->_t('plugin_name');
        }
        
        /**
         * get string with plugin description (taken from plugin language file)
         * @return string
         */
        public function getDescription(){
            return $this->_t('description');
        }
        /**
         * get array read from info.json
         * @return type
         */
        public function getPluginInfos(){
    
            if ($this->_aPlugininfos){
                return $this->_aPlugininfos;
            }
            
            $oReflection=new ReflectionClass($this);
            $sFile=dirname($oReflection->getFileName()) . '/info.json';
            $this->_aPlugininfos= (file_exists($sFile))
                ? json_decode(file_get_contents($sFile), 1)
                : array('error'=> 'unable to read info file ['.$sFile.'].')
            ;
            return $this->_aPlugininfos;
        }
    
        // ----------------------------------------------------------------------
        // INTERFACE :: RENDERER
        // ----------------------------------------------------------------------
        public function renderCfgExample(){
            $sReturn='';
            $sPre='                ';
            
            $aInfos=$this->getPluginInfos();
            $sReturn.='<pre>$aConfig = array(
        ...
        \'plugins\'=>array(
            ...
            // enabled rollout plugins
            \'rollout\'=>array(
                ...
                <strong>
                \''.$this->getId().'\'=>array(
                    // '.$this->getName().'
                    // '.$this->getDescription().'
                    '.PHP_EOL;
            
            // add global vars
            if(!isset($aInfos['vars']['global']) || !count($aInfos['vars']['global'])){
                $sReturn.=$sPre.'// this plugin has no global config vars'.PHP_EOL;
            } else {
                foreach ($aInfos['vars']['global'] as $sVar=>$aItem){
                    $sReturn.=$sPre.'// '.$this->_t($sVar.'-hint').PHP_EOL;
                    $sReturn.=$sPre.'\''.$sVar.'\'=>\''.(isset($this->_aCfgGlobal[$sVar]) ? $this->_aCfgGlobal[$sVar] : $aItem['default']).'\','.PHP_EOL;
                    $sReturn.=PHP_EOL;
                }
            }
            
            $sReturn.='
                ),
                </strong>
                ...
            ),
            ...
        ),
    );</pre>';
            return $sReturn;
        }
        protected function _renderMoreToggler($sContent){
            $sDivId='rollout-more-toggler-'.$this->getId().'-'.md5($sContent);
            return ''
                    . '<button onclick="$(\'#'.$sDivId.'\').slideToggle(); return false;" class="btn btn-secondary"> ... </button>'
                    . '<div id="'.$sDivId.'" style="display: none;">'
                        . $sContent
                    . '</div>'
                    ;
            
        }
        public function renderFormdata4Project() {
            return ''
                    . $this->_renderForm4Vars('project', false)
                    . $this->_renderForm4Vars('global', false)
                    // . $this->_renderFormProjectVars($this->_sNamePrefix4Project, false)
                    // . '<pre>DEBUG: GLOBAL settings - $this->_aCfgGlobal = ' . print_r($this->_aCfgGlobal, 1) . '</pre>'
                    // . '<pre>DEBUG: PROJECT settings - $this->getConfig() = ' . print_r($this->getConfig(), 1) . '</pre>'
            // .'<pre>DEBUG: $this->_aCfgProject ... plugin = '.print_r($this->_aCfgProject, 1).'</pre>'
            ;
        }
        public function renderFormdata4Phase($sPhase){
            static $iCounter;
            if(!isset($iCounter)){
                $iCounter=0;
            }
            $sDivId='rollout-override-div-'.$this->getId().'-'.$sPhase.'-'.$iCounter;
            return ''
                . $this->_renderForm4Vars('phase', $sPhase)
                . $this->_renderMoreToggler(
                    $this->_renderForm4Vars('project', $sPhase)
                    . $this->_renderForm4Vars('global', $sPhase)
                )
                // . $this->_renderForm($aFormdata, 'project')
                // .$sReturn
                // . '<pre>DEBUG: GLOBAL settings - $this->_aCfgGlobal = ' . print_r($this->_aCfgGlobal, 1) . '</pre>'
                // . '<pre>DEBUG: PROJECT settings - $this->getConfig() = ' . print_r($this->getConfig(), 1) . '</pre>'
                // . '<pre>DEBUG: PHASE settings - $this->getConfig("'.$sMyPhase.'") = ' . print_r($this->getConfig($sMyPhase), 1) . '</pre>'
                ;
        }
    }