Select Git revision
project.class.php
project.class.php 32.80 KiB
<?php
/**
* class for single project
*/
class project {
// ----------------------------------------------------------------------
// CONFIG
// ----------------------------------------------------------------------
/**
* config file
* @var type
*/
private $_sCfgfile = "../config/inc_projects_config.php";
/**
* configuration ($aConfig in the config file)
* @var array
*/
private $_aConfig = array();
/**
* configuration of the project (= $aProjects[ID] in the config file)
* @var array
*/
private $_aPrjConfig = array();
/**
* version infos of all phases
* @var type
*/
private $_aData = array();
/**
* existing versions in the archive dir
* @var type
*/
private $_aVersions = array();
/**
* places of version infos in each deployment phase
* @var type
*/
private $_aPlaces = array(
"onhold" => "Queue",
"ready4deployment" => "Repo",
"deployed" => "Installiert",
);
private $_iRcAll = 0;
// ----------------------------------------------------------------------
// constructor
// ----------------------------------------------------------------------
/**
* constructor
* @param string $sId id of the project
*/
public function __construct($sId = false) {
$this->_readConfig();
if ($sId)
$this->setProjectById($sId);
}
// ----------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------
/**
* read default config file
* @return boolean
*/
private function _readConfig() {
require(__dir__ . '/' . $this->_sCfgfile);
$this->_aConfig = $aConfig;
return true;
}
/**
* validate config data
* @return boolean
*/
private function _verifyConfig() {
if (!count($this->_aPrjConfig))
die("ERROR::CONFIG: no config was for found the project. check $aProjects in config file.");
if (!array_key_exists("packageDir", $this->_aConfig))
die("ERROR::CONFIG: packagedir is not defined.");
if (!$this->_aConfig["packageDir"])
die("ERROR::CONFIG: packagedir is not set.");
if (!file_exists($this->_aConfig["packageDir"]))
die("ERROR::CONFIG: packagedir does not exist: "" . $this->_aConfig['packageDir'] . "".");
if (!array_key_exists("archiveDir", $this->_aConfig))
die("ERROR::CONFIG: key "archiveDir" was not found in config.");
if (!$this->_aConfig["archiveDir"])
die("ERROR::CONFIG: archiveDir is not set.");
if (!file_exists($this->_aConfig["archiveDir"]))
die("ERROR::CONFIG: archiveDir does not exist: "" . $this->_aConfig['archiveDir'] . "".");
if (!array_key_exists("phases", $this->_aPrjConfig))
die("ERROR::CONFIG: key "phases" was not found in config.<br><pre>" . print_r($this->_aPrjConfig, true) . "</pre>");
// TODO: verify ausbauen
return true;
}
/**
* execute a commandline; returns a string of output of timestamp, command, output and returncode
* @param string $sCommand
* @return string
*/
private function _execAndSend($sCommand) {
$sReturn = '';
$bUseHtml = $_SERVER ? true : false;
ob_implicit_flush(true);
// ob_end_flush();
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
flush();
$process = proc_open($sCommand, $descriptorspec, $pipes, realpath('./'), array());
$sReturn.="[" . date("H:i:s d.m.Y") . "] ";
$sReturn.=$bUseHtml ? "<strong>$sCommand</strong>" : "$sCommand";
$sReturn.=$bUseHtml ? "<br>" : "\n";
$sErrors = false;
if (is_resource($process)) {
while ($s = fgets($pipes[1])) {
$sReturn.=$s;
flush();
}
while ($s = fgets($pipes[2])) {
$sErrors.=$s;
flush();
}
}
if ($sErrors)
$sReturn.="STDERR:\n" . $sErrors;
$oStatus = proc_get_status($process);
$iRc = $oStatus['exitcode'];
$this->_iRcAll += $iRc;
$sReturn.="[" . date("H:i:s d.m.Y") . "] exitcode " . $iRc;
if ($bUseHtml) {
if ($iRc == 0) {
$sReturn = "<pre>" . $sReturn;
} else {
$sReturn = '<pre class="error">' . $sReturn;
}
$sReturn.='</pre>';
}
flush();
return $sReturn;
}
// ----------------------------------------------------------------------
// GETTER
// ----------------------------------------------------------------------
/**
* get a temp directory
* @return string
*/
private function _getTempDir() {
return $s = $this->_getBuildDir() . '/' . $this->_aPrjConfig["fileprefix"] . "_" . date("Ymd-His");
}
private function _getBuildDir(){
return $this->_aConfig['buildDir'].'/'.$this->_aConfig["id"];
}
/**
* get directory for infofile and package (without extension)
* @param string $sPhase one of preview|stage|live ...
* @param string $sPlace one of onhold|ready4deployment|deployed
* @return string
*/
private function _getFileBase($sPhase, $sPlace) {
if (!array_key_exists($sPhase, $this->_aConfig["phases"])) {
die("ERROR: _getFileBase - this phase does not exist: $sPhase.");
}
if (!array_key_exists($sPlace, $this->_aPlaces)) {
die("ERROR: _getFileBase - this place does not exist: $sPhase.");
}
// local file for onhold|ready4deployment
$sBase = $this->_aConfig['packageDir'] . "/" . $sPhase . "/" . $this->_aPrjConfig["fileprefix"];
if ($sPlace == "onhold")
$sBase.="_onhold";
// $sBase .= "/" . $this->_aPrjConfig["fileprefix"];
// url for deployed
if ($sPlace == "deployed") {
if ($this->isActivePhase($sPhase) && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) {
$sBase = $this->_aPrjConfig["phases"][$sPhase]["url"] . $this->_aPrjConfig["fileprefix"];
} else {
$sBase = '';
}
}
return $sBase;
}
/**
* get filename for info file
* @param string $sPhase one of preview|stage|live ...
* @param string $sPlace one of onhold|ready4deployment|deployed
* @return string
*/
private function _getInfofile($sPhase, $sPlace) {
$sBase = $this->_getFileBase($sPhase, $sPlace);
return $sBase ? $sBase .'/'.$this->_aPrjConfig["fileprefix"] . '.json' : false;
}
/**
* get filename for package file
* @param string $sPhase one of preview|stage|live ...
* @param string $sPlace one of onhold|ready4deployment|deployed
* @return string
*/
private function _getPackagefile($sPhase, $sPlace) {
$sBase = $this->_getFileBase($sPhase, $sPlace);
return $sBase ? $sBase .'/'.$this->_aPrjConfig["fileprefix"] . '.tgz' : false;
}
private function _getArchiveDir($sTimestamp) {
if (!$sTimestamp) {
die("ERROR: getArchiveDir timestamp is required");
}
return $this->_getProjectArchiveDir() . '/' . $sTimestamp;
}
/**
* get the directory for archive files of this project
* @return string
*/
public function _getProjectArchiveDir() {
return $this->_aConfig["archiveDir"] . '/' . $this->_aConfig["id"];
}
/**
* get all existing versions in archive and its usage
* versions are array keys; where they are used is written in values
* @return array
*/
public function getVersions(){
// --- read all file entries
$aReturn=array();
$sDir=$this->_getProjectArchiveDir();
foreach (scandir($this->_getProjectArchiveDir()) as $sEntry){
if (is_dir($sDir.'/'.$sEntry) && $sEntry != '.' && $sEntry != '..') $aReturn[$sEntry]=false;
}
$this->_aVersions=$aReturn;
// --- check version in all phases
$this->getAllPhaseInfos();
foreach ($this->_aData["phases"] as $sPhase=>$aData){
foreach(array_keys($this->_aPlaces) as $sPlace){
if (array_key_exists($sPlace, $aData) && array_key_exists("version", $aData[$sPlace])){
$this->_aVersions[$aData[$sPlace]["version"]][]=$sPlace;
}
}
}
ksort($this->_aVersions);
return $this->_aVersions;
}
/**
* recursive delete
* @param type $dir
* @return type
*/
private function _rmdir($dir) {
foreach (scandir($dir) as $sEntry){
if (is_dir($dir.'/'.$sEntry) && $sEntry != '.' && $sEntry != '..') {
$this->_rmdir($dir.'/'.$sEntry);
}
else
unlink($dir.'/'.$sEntry);
}
return rmdir($dir);
}
/**
* cleanup of archive directory; it returns the list of deleted
* directories as array
* @return array
*/
public function cleanupArchive(){
$aUnused=array();
$sDir=$this->_getProjectArchiveDir();
$this->getVersions();
$aDelete=array();
// find unused versions
foreach ($this->_aVersions as $sVersion=>$aUsage){
if (!$aUsage || count($aUsage)==0){
$aUnused[]=$sVersion;
}
}
// keep a few
while (count($aUnused)>$this->_aConfig["versionsToKeep"]){
$sVersion=array_shift($aUnused);
$sDir2=$sDir.'/'.$sVersion;
if ($this->_rmdir($sDir2)){
$aDelete[]=$sDir2;
} else {
echo "Warning: unable to delete Archive $sDir2<br>";
};
}
// rescan versions
if (count($aDelete)) {
$this->getVersions();
}
return $aDelete;
}
/**
* cleanup of archive directory; it returns the list of deleted
* directories as array
* @return array
*/
public function cleanupBuilds(){
$sDir=$this->_getBuildDir();
$aDirlist=array();
$aDelete=array();
foreach (scandir($sDir) as $sEntry){
if (is_dir($sDir.'/'.$sEntry) && $sEntry != '.' && $sEntry != '..') $aDirlist[]=$sEntry;
}
// keep a few
while (count($aDirlist)>$this->_aConfig["builtsToKeep"]){
$sVersion=array_shift($aDirlist);
$sDir2=$sDir.'/'.$sVersion;
if ($this->_rmdir($sDir2)){
$aDelete[]=$sDir2;
} else {
echo "Warning: unable to delete Build $sDir2<br>";
};
}
return $aDelete;
}
/**
* get conmplete config of the project
* @return array
*/
public function getConfig() {
return $this->_aPrjConfig;
}
/**
* get name/ label of the project
* @return string
*/
public function getLabel() {
return $this->_aPrjConfig["label"];
}
/**
* get description of the project
* @return string
*/
public function getDescription() {
return $this->_aPrjConfig["description"];
}
/**
* get deploy and queue infos for all phases
* @return type
*/
public function getAllPhaseInfos() {
if (!array_key_exists("phases", $this->_aData))
$this->_aData["phases"] = array();
foreach (array_keys($this->_aConfig["phases"]) as $sPhase) {
if (!array_key_exists($sPhase, $this->_aData["phases"])) {
$this->getPhaseInfos($sPhase);
}
}
return $this->_aData["phases"];
}
/**
* get statusinfos of a named phase
* @param string $sPhase name of the phase; one of preview|stage|live
* @return array
*/
public function getPhaseInfos($sPhase) {
if (!$sPhase){
die("ERROR: project->getPhaseInfos - parameter for phase is required");
}
if (!array_key_exists("phases", $this->_aData))
$this->_aData["phases"] = array();
if (!array_key_exists($sPhase, $this->_aData["phases"])) {
$this->_aData["phases"][$sPhase] = array();
$aTmp = array();
// a blocked package is waiting for deployment timeslot?
$sKey = "onhold";
$sJsonfile = $this->_getInfofile($sPhase, $sKey);
$aTmp[$sKey] = array();
if (file_exists($sJsonfile)) {
$aJson = json_decode(file_get_contents($sJsonfile), true);
if (array_key_exists("timestamp", $aJson)) {
$aTmp[$sKey] = $aJson;
$aTmp[$sKey]["infofile"] = $sJsonfile;
$aTmp[$sKey]["version"] = $aJson["timestamp"];
$aTmp[$sKey]["ok"] = 1;
} else {
$aTmp[$sKey]["error"] = "info file $sJsonfile exists but is corrupt (no timestamp)." . print_r($aJson, true);
}
} else {
$aTmp[$sKey]["info"] = "No package is waiting in the queue.";
$aTmp[$sKey]["ok"] = 1;
}
// package for puppet
$sKey = "ready4deployment";
$sJsonfile = $this->_getInfofile($sPhase, $sKey);
$aTmp[$sKey] = array();
if (file_exists($sJsonfile)) {
$sPkgfile = $this->_getPackagefile($sPhase, $sKey);
if (file_exists($sPkgfile)) {
$aJson = json_decode(file_get_contents($sJsonfile), true);
if (array_key_exists("timestamp", $aJson)) {
$aTmp[$sKey] = $aJson;
$aTmp[$sKey]["infofile"] = $sJsonfile;
$aTmp[$sKey]["packagefile"] = $sPkgfile;
$aTmp[$sKey]["version"] = $aJson["timestamp"];
$aTmp[$sKey]["ok"] = 1;
} else {
$aTmp[$sKey]["error"] = "info file $sJsonfile exists but is corrupt (no timestamp)." . print_r($aJson, true);
}
} else {
$aTmp[$sKey]["error"] = "package file was not found: $sPkgfile";
}
} else {
$aTmp[$sKey]["error"] = "info file was not found: $sJsonfile";
}
// published data
$sKey = "deployed";
$sJsonfile = $this->_getInfofile($sPhase, $sKey);
$aTmp[$sKey] = array();
if ($this->isActivePhase($sPhase)) {
$sJsonUrl = $this->_aPrjConfig["phases"][$sPhase]["url"] . $this->_aPrjConfig["fileprefix"] . ".json";
$sJsonData = @file_get_contents($sJsonUrl);
if ($sJsonData) {
$aJson = json_decode($sJsonData, true);
if (array_key_exists("timestamp", $aJson)) {
$aTmp[$sKey] = $aJson;
$aTmp[$sKey]["infofile"] = $sJsonUrl;
$aTmp[$sKey]["version"] = $aJson["timestamp"];
$aTmp[$sKey]["ok"] = 1;
} else {
$aTmp[$sKey]["error"] = "json url was readable <a href=$sJsonUrl>$sJsonUrl</a> but is corrupt (no timestamp)." . print_r($aJson, true);
}
} else {
$aTmp[$sKey]["error"] = "json url not readable <a href=$sJsonUrl>$sJsonUrl</a>";
}
} else {
$aTmp[$sKey]["warning"] = "this phase is not active or has no url";
}
$this->_aData["phases"][$sPhase] = $aTmp;
}
return $this->_aData["phases"][$sPhase];
}
/**
* check if the given phase is active for this project
* @param type $sPhase
* @return type
*/
public function isActivePhase($sPhase) {
return (
array_key_exists($sPhase, $this->_aPrjConfig["phases"])
&& array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])
&& $this->_aPrjConfig["phases"][$sPhase]["url"]
);
}
/**
* find the next active phase of a project
* @param string $sPhase current phase; if empty the function sends back the first phase
*/
public function getNextPhase($sPhase = false) {
if ($sPhase) {
if (!array_key_exists($sPhase, $this->_aConfig["phases"])) {
die("ERROR: this phase does not exist: $sPhase.");
}
}
$sNextPhase = false;
$bUseNextPhase = $sPhase ? false : true;
foreach (array_keys($this->_aConfig["phases"]) as $s) {
if ($bUseNextPhase) {
if ($this->isActivePhase($s)) {
$sNextPhase = $s;
$bUseNextPhase = false;
continue;
}
}
if ($sPhase == $s) {
$bUseNextPhase = true;
}
}
return $sNextPhase;
}
/**
* check: is the deployment to the next phase enabled for this phase?
* @param type $sPhase
*/
public function canAcceptPhase($sPhase = false) {
if (!$sPhase) {
$sNext = $this->getNextPhase($sPhase);
return $sNext > '';
}
if (!array_key_exists($sPhase, $this->_aConfig["phases"])) {
die("ERROR: in canDeploy this phase does not exist: $sPhase.");
}
if (!$this->isActivePhase($sPhase)) {
// die("ERROR: the phase $sPhase is not active in this project.");
return false;
}
$sNext = $this->getNextPhase($sPhase);
if (!$sNext)
return false;
// ensure that _aData is filled
$this->getPhaseInfos($sPhase);
// array key "ok" must be in the ready4deployment and deployed info
if (
array_key_exists($sPhase, $this->_aData["phases"]) && array_key_exists("onhold", $this->_aData["phases"][$sPhase]) && array_key_exists("ready4deployment", $this->_aData["phases"][$sPhase]) && array_key_exists("deployed", $this->_aData["phases"][$sPhase]) && array_key_exists("ok", $this->_aData["phases"][$sPhase]["onhold"]) && array_key_exists("ok", $this->_aData["phases"][$sPhase]["ready4deployment"]) && array_key_exists("ok", $this->_aData["phases"][$sPhase]["deployed"])
)
return true;
return false;
}
// ----------------------------------------------------------------------
// SETTER
// ----------------------------------------------------------------------
/**
* apply a config
* @param array $aConfig
* @return boolean
public function setConfig($aConfig) {
$this->_aConfig = $aConfig;
$this->_verifyConfig();
return true;
}
*/
/**
* apply a config
* @param array $aConfig
* @return boolean
*/
public function setProjectById($sId) {
$this->_aPrjConfig = array();
require(__dir__ . '/' . $this->_sCfgfile);
if (!array_key_exists("$sId", $aProjects)) {
die("ERROR: a project with ID $sId does not exist.");
}
$this->_aPrjConfig = $aProjects[$sId];
$this->_aConfig["id"] = $sId;
$this->_verifyConfig();
return true;
}
// ----------------------------------------------------------------------
// ACTIONS
// ----------------------------------------------------------------------
/**
* get html code of a div around a message
* @param string $sWarnlevel one of error|success|info|warning to get a colored box
* @param string $sMessage message txt
* @return string
*/
public function getBox($sWarnlevel, $sMessage){
$aCfg=array(
"error"=>array("class"=>"alert alert-error", "prefix"=>"ERROR :-("),
"success"=>array("class"=>"alert alert-success", "prefix"=>"SUCCESS :-)"),
"info"=>array("class"=>"alert alert-info", "prefix"=>"INFO"),
"warning"=>array("class"=>"alert alert-block", "prefix"=>"WARNING"),
);
$sClass="";
$sPrefix="";
if (array_key_exists($sWarnlevel, $aCfg)){
$sClass=$aCfg[$sWarnlevel]["class"];
$sPrefix=$aCfg[$sWarnlevel]["prefix"];
$sMessage='<strong>'.$aCfg[$sWarnlevel]["prefix"].'</strong> ' . $sMessage;
}
return '
<div class="'.$sClass.'">
'.$sMessage.'
</div>';
}
/**
* Build a new package for the deployment. It will be put to the queue
* of the first active phase (i.e. preview).
* If there is no deployment time range it will be deployed too.
* @global type $aParams
* @return boolean|string
*/
public function build() {
global $aParams;
$sReturn = false;
$this->_iRcAll = 0;
// --------------------------------------------------
// create workdir
// --------------------------------------------------
$aDirs=$this->cleanupBuilds();
if (count($aDirs))
$sReturn.='<h2>Cleanup older failed builds</h2><pre>'.print_r($aDirs, true).'</pre>';
$sTempDir = $this->_getTempDir();
$sFirstLevel = $this->getNextPhase();
if (!$sFirstLevel) return false;
$sReturn.="<h2>Create a temporary build dir</h2>";
if (!file_exists($sTempDir)) {
$sReturn.=$this->_execAndSend("mkdir -p " . $sTempDir);
}
$sReturn.=$this->_execAndSend("ls -ld " . $sTempDir);
if (!file_exists($sTempDir)) {
return $this->getBox("error", "$sTempDir was not created.". $sReturn);
}
// --------------------------------------------------
// checkout
// --------------------------------------------------
switch ($this->_aPrjConfig["build"]["type"]) {
case "git":
$sReturn.="<h2>Checkout a GIT project</h2>";
// $sReturn.=$this->_execAndSend("find " . $this->_aConfig["workDir"]);
$sReturn.=$this->_execAndSend("cd $sTempDir && git init");
$sKeyfile = dirname(dirname(__file__)) . "/" . $this->_aPrjConfig["build"]["keyfile"];
$sWrapper = dirname(dirname(dirname(dirname(__file__)))) . "/shellscripts/gitsshwrapper.sh";
// $sReturn.=$this->_execAndSend("ls -l " . $sWrapper);
// $sReturn.=$this->_execAndSend("ls -l ".$sKeyfile);
$sReturn.=$this->_execAndSend("cd $sTempDir && export GIT_SSH=$sWrapper ; export PKEY=$sKeyfile; git pull " . $this->_aPrjConfig["build"]["ssh"]);
// $sVersion=$this->_execAndSend("cd $sTempDir && export GIT_SSH=$sWrapper ; export PKEY=$sKeyfile; git pull " . $this->_aPrjConfig["build"]["ssh"]);
// control: directory listing after checkout
$sReturn.=$this->_execAndSend("ls -lisa $sTempDir");
// fetch version infos
$sVersioninfo = str_replace("\n", "<br>", shell_exec("cd $sTempDir && git log -1"));
$sReturn.=$this->getBox("info", $sVersioninfo);
break;
default:
return $this->getBox("error", "Build Type not supported: " . $this->_aPrjConfig["build"]["type"]. $sReturn);
}
if (!$this->_iRcAll == 0) {
return $this->getBox("error", "checkout failed.</h3>One of the commands failed (see above).<br>You can ask the sysadmins and analyze with them the created temp directory "' . $sTempDir . '".". $sReturn);
}
$sReturn.=$this->getBox("success", "Checkout OK!");
// --------------------------------------------------
// execute hook
// --------------------------------------------------
$sHookfile = $this->_aConfig['hooks']['build-aftercheckout'];
$sReturn.='<h2>Execute Hook ' . $sHookfile . '</h2>';
if (file_exists($sTempDir . '/' . $sHookfile)) {
$sReturn.=$this->_execAndSend('cd ' . $sTempDir . ' && chmod 755 hooks/on*');
$sReturn.=$this->_execAndSend('cd ' . $sTempDir . ' && "' . $sHookfile . '"');
if (!$this->_iRcAll == 0) {
return $this->getBox("error", "executing hook failed. One of the commands failed.<br>You can ask the sysadmins and analyze with them the created temp directory "' . $sTempDir . '".". $sReturn);
}
} else {
$sReturn.='SKIP. Hook was not found.<br>';
}
// --------------------------------------------------
// TODO: cleanup .git, .svn, ...?
// wenn es kein .git gibt, bricht er ab...
// --------------------------------------------------
$sReturn.="<h2>cleanup project</h2>";
$sReturn.=$this->_execAndSend("cd $sTempDir && rm -rf .git");
$sReturn.=$this->_execAndSend("cd $sTempDir && rm -rf .svn");
// public_html must exist
$sWebroot = $sTempDir . '/public_html';
if (!file_exists($sWebroot)) {
return $this->getBox("error", "a subdir "public_html" does not exist.". $sReturn);
}
if (!$this->_iRcAll == 0) {
return $this->getBox("error", "build failed - working directory has errors and is not ready to create package.<br>You can ask the sysadmins and analyze with them the created temp directory "$sTempDir"". $sReturn);
}
$sReturn.=$this->getBox("success", "preparations ok - directory is ready for packaging now.");
// --------------------------------------------------
// create package
// --------------------------------------------------
$sReturn.='<h2>Create package</h2>';
// generate info file
$sTs = date("Y-m-d H:i:s");
$sTs2 = date("Ymd_His");
$sInfoFileWebroot = $sWebroot . '/' . basename($this->_getInfofile($sFirstLevel, "deployed"));
$sInfoFileArchiv = $this->_getArchiveDir($sTs2) . '/' . basename($this->_getInfofile($sFirstLevel, "deployed"));
$sPackageFileArchiv = $this->_getArchiveDir($sTs2) . '/' . basename($this->_getPackagefile($sFirstLevel, "deployed"));
$sInfos = '{
"date": "' . $sTs . '",
"timestamp": "' . $sTs2 . '",
"revision": "' . $sVersioninfo . '",
"user": "' . $aParams["inputUser"] . '",
"remark": "' . $aParams["inputComment"] . '"
}';
$sReturn.="writing info file into webroot...<br>";
file_put_contents($sInfoFileWebroot, $sInfos);
$sReturn.=$this->_execAndSend("ls -l $sInfoFileWebroot");
if (!file_exists(dirname($sPackageFileArchiv))) {
$sReturn.="* create " . dirname($sPackageFileArchiv) . "<br>";
mkdir(dirname($sPackageFileArchiv), 0775, true);
}
$sReturn.=$this->_execAndSend("ls -ld " . dirname($sPackageFileArchiv));
if (!file_exists(dirname($sPackageFileArchiv))) {
return $this->getBox("error", "directory was not created: " . dirname($sPackageFileArchiv) . $sReturn);
return $sReturn;
}
$sReturn.="create archive $sPackageFileArchiv<br>";
$sReturn.=$this->_execAndSend("cd $sTempDir && tar -czf $sPackageFileArchiv .");
$sReturn.="writing info file into archive...<br>";
file_put_contents($sInfoFileArchiv, $sInfos);
$sReturn.="<br>Created Archive files:<br>";
$sReturn.=$this->_execAndSend("ls -l $sPackageFileArchiv $sInfoFileArchiv");
if (!$this->_iRcAll == 0) {
return $this->getBox("error", 'creation failed One of the commands failed (see below).<br>You can ask the sysadmins and analyze with them the created temp directory "' . $sTempDir . '".' . $sReturn);
}
$sReturn.="<h2>cleanup $sTempDir</h2>";
$sReturn.="<h3>cleanup $sTempDir</h3>";
$sReturn.=$this->_execAndSend("rm -rf $sTempDir");
$sReturn.="<h3>cleanup Archive</h3>removing the oldest unused packages ...";
$sReturn.='<pre>'. print_r($this->cleanupArchive(), true).'</pre>';
$sReturn.=$this->getBox("success", "Build finished successfully.");
// TODO: force synch archive to puppet master
$sReturn.=$this->queue($sFirstLevel, $sTs2);
return $sReturn;
}
/**
* put a packaged version into the queue of a specified phase
* @param string $sPhase name of the phase
* @param string $sVersion version
* @return string
*/
public function queue($sPhase, $sVersion) {
if (!$this->isActivePhase($sPhase)) return false;
$sReturn="<h2>Queue to $sPhase</h2>";
$sPlace="onhold";
$sLinkTarget = $this->_getArchiveDir($sVersion);
$sLinkName = $this->_getFileBase($sPhase, $sPlace);
// --------------------------------------------------
// Checks
// --------------------------------------------------
if (!$sLinkName) {
die("ERROR: Queuing failed - sLinkName is empty.");
}
if (!$sLinkTarget) {
die("ERROR: Queuing failed - sLinkTarget is empty.");
}
if (!file_exists($sLinkTarget)) {
die("ERROR: Queuing failed - version $sVersion is invalid. The directory $sLinkTarget does not exist.");
}
// --------------------------------------------------
// create the new link
// --------------------------------------------------
$this->_iRcAll = 0;
if (file_exists($sLinkName)) {
$sReturn.="removing existing version<br>";
$sReturn.=$this->_execAndSend("rm -f $sLinkName");
}
$sReturn.="linking to new version <br>";
$sReturn.=$this->_execAndSend("ln -s $sLinkTarget $sLinkName");
$sReturn.=$this->_execAndSend("ls -l $sLinkName | fgrep $sLinkTarget");
if (!$this->_iRcAll == 0) {
return $this->getBox("error", 'Queuing failed One of the commands failed.' . $sReturn);
}
$sReturn.=$this->getBox("success", "the version $sVersion was set to place $sPlace");
$sReturn.=$this->deploy($sPhase);
return $sReturn;
}
/**
* deploy a queued package - this moves the queue into the repo directory
* and will be installed on server within 30 min
* @param type $sTargetphase
* @return boolean|string
*/
public function deploy($sTargetphase) {
if (!$this->isActivePhase($sTargetphase)) return false;
$sReturn="<h2>Deploy to $sTargetphase</h2>";
$sQueueLink = $this->_getFileBase($sTargetphase, "onhold");
$sRepoLink = $this->_getFileBase($sTargetphase, "ready4deployment");
if (array_key_exists("deploytimes", $this->_aConfig["phases"][$sTargetphase])){
// check if the a deploy time is reached
$sNow=date("D H:i:s");
$sReturn.="check if one of the deployment times is reached and matches $sNow<br>";
$bCanDeploy=false;
foreach ($this->_aConfig["phases"][$sTargetphase]["deploytimes"] as $sRegex){
$sReturn.="... $sRegex<br>";
if (preg_match($sRegex, $sNow)){
$bCanDeploy=true;
}
}
if (!$bCanDeploy){
$sReturn.="SKIP: deployment time was not reached.<br>";
return $sReturn;
}
$sReturn.="OK, deployment time was reached.<br>";
// if ()
}
if (!file_exists($sQueueLink)){
$sReturn.=$this->getBox("warning", "SKIP: nothing to do - the current queue is empty ($sQueueLink does not exist).");
return $sReturn;
}
if (!file_exists($sQueueLink)){
$sReturn.="SKIP: no current queue - $sQueueLink does not exist.";
return $sReturn;
}
// --------------------------------------------------
// move the queue link to the repo name
// --------------------------------------------------
$this->_iRcAll = 0;
if (file_exists($sRepoLink)) {
$sReturn.="removing existing version<br>";
$sReturn.=$this->_execAndSend("rm -f $sRepoLink");
}
$sReturn.="moving queue to repo<br>";
$sReturn.=$this->_execAndSend("mv $sQueueLink $sRepoLink");
if (!$this->_iRcAll == 0) {
return $this->getBox("error", "Deployment failed - One of the commands failed." . $sReturn);
}
// TODO: force synch to puppet master
$sReturn.=$this->getBox("success", "SUCCESS: deployment was done and will be installed soon.");
return $sReturn;
}
}
?>