Skip to content

Instantly share code, notes, and snippets.

@mhuber84
Last active August 29, 2015 14:03
Show Gist options
  • Save mhuber84/38f2a97e1ed3691b6e79 to your computer and use it in GitHub Desktop.
Save mhuber84/38f2a97e1ed3691b6e79 to your computer and use it in GitHub Desktop.
TYPO3 Surf deployment for TYPO3 CMS with 4 target nodes
<?php
$GLOBALS['TYPO3_CONF_VARS']['BE']['installToolPassword'] = '$P$CEF2NP3kCoIHwDupr8RiYUMQ7/Rp.j.';
$GLOBALS['TYPO3_CONF_VARS']['DB']['database'] = 'projects_my_multiplenodes';
$GLOBALS['TYPO3_CONF_VARS']['DB']['username'] = 'user';
$GLOBALS['TYPO3_CONF_VARS']['DB']['password'] = 'secret';
$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] = 'My MultipleNodes';
$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] = TRUE;
$GLOBALS['TYPO3_CONF_VARS']['FE']['debug'] = TRUE;
$GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'] = '*';
$GLOBALS['TYPO3_CONF_VARS']['SYS']['displayErrors'] = TRUE;
$GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog'] = 'file';
$GLOBALS['TYPO3_CONF_VARS']['SYS']['sqlDebug'] = 1;
$GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLogLevel'] = 0;
$localconfDir = dirname(__FILE__);
if (file_exists($localconfDir . '/iniset.php')) {
include_once($localconfDir . '/iniset.php');
}
?>
<?php
$deploymentName = 'My.MultipleNodes.LiveDeployment';
$applicationName = 'My.MultipleNodes';
// SSH username. Authentication via private/public key
$username = 'user';
// Url to the project git repository
$repositoryUrl = 'ssh://host.com/git/my/mutliplenodes.git';
// Path to the TYPO3 source on the server
$typo3srcPath = '/data/TYPO3/CMS/TYPO3_6-2-3';
// Path to the shared/editorial files on the server
$filesPath = '/data/projects/My/MultipleNodes/files';
// URLs for smoke tests
$backendURL = 'http://multiplenodes.my.projects.localhost/typo3';
$backendURLAdditionalCurlParameters = '';
$frontendURL = 'http://multiplenodes.my.projects.localhost';
$frontendURLAdditionalCurlParameters = '';
// The deployment path is not the document root!
// The document root has to be: '[deploymentPath]/releases/current'.
$deploymentPath = '/data/projects/My/MultipleNodes/deployment';
/**
* The host on which we want to do the database compare.
*/
// A speaking name to identify this host
$dbHost = 'server1';
// Hostname, used to connect via ssh
$dbHostname = 'server1.multiplenodes.my.projects.localhost';
// Port, used to connect via ssh
$dbPort = '22';
// Database connection configuration on this host (f.e. used for backups)
$dbconHost = 'localhost';
$dbconPort = '3306';
$dbconUsername = 'user';
$dbconPassword = 'secret';
$dbconDatabase = 'projects_my_multiplenodes';
/**
* Other hosts
* Array of hostnames, also yoused to connect via ssh
*/
$hosts = array(
'server2' => array(
'hostname' => 'server2.multiplenodes.my.projects.localhost',
'port' => '22',
),
'server3' => array(
'hostname' => 'server3.multiplenodes.my.projects.localhost',
'port' => '22',
),
'server4' => array(
'hostname' => 'server4.multiplenodes.my.projects.localhost',
'port' => '22',
),
);
?>
<?php
ini_set('realpath_cache_size', '0');
ini_set('realpath_cache_ttl', '0');
clearstatcache();
clearstatcache(TRUE);
?>
<?php
echo "\n";
echo "############################################################################\n";
echo "# Have you testet the deployment with My.MultipleNodes.LiveTestDeployment? #\n";
echo "############################################################################\n";
echo "Type 'yes' or 'no' and hit ENTER:\n";
echo "\n";
$handle = fopen("php://stdin", "r");
$line = fgets($handle);
echo "Your answer was " . trim($line) . "!\n";
if (trim($line) != 'yes') {
echo "ABORTING!\n";
echo "\n";
exit();
}
echo "STARTING!\n";
echo "\n";
/** @var \TYPO3\Surf\Domain\Model\Deployment $deployment */
/**
* config.php is not versionized with git so we can have different configs to develop this deployment script
*/
$deploymentConfigPathAndFilename = FLOW_PATH_ROOT . 'Build/Surf/Resources/My.MultipleNodes.LiveDeployment/config.php';
if (!file_exists($deploymentConfigPathAndFilename)) {
exit(sprintf("The deployment config file %s does not exist.\n", $deploymentConfigPathAndFilename));
}
require_once($deploymentConfigPathAndFilename);
/**
* One Application for all other Nodes
*/
$application = new \TYPO3\Surf\Application\BaseApplication($applicationName . ' without DatabaseCompare');
$application->setOption('repositoryUrl', $repositoryUrl);
$application->setOption('transferMethod', 'rsync');
$application->setOption('rsyncFlags', '--recursive --times --perms --links --delete --delete-excluded --exclude \'.git\' --exclude \'.sass-cache\'');
$application->setOption('packageMethod', 'git');
$application->setOption('updateMethod', NULL);
$application->setOption('branch', 'master');
$application->setDeploymentPath($deploymentPath);
foreach ($hosts as $host => $hostData) {
$node = new \TYPO3\Surf\Domain\Model\Node($host);
$node->setHostname($hostData['hostname']);
$node->setOption('port', $hostData['port']);
$node->setOption('username', $username);
$application->addNode($node);
}
$deployment->addApplication($application);
/**
* One Application for the Node on which we want to do the database updates
*/
$dbApplication = new \TYPO3\Surf\Application\BaseApplication($applicationName . ' with DatabaseCompare');
$dbApplication->setOption('repositoryUrl', $repositoryUrl);
$dbApplication->setOption('transferMethod', 'rsync');
$dbApplication->setOption('rsyncFlags', '--recursive --times --perms --links --delete --delete-excluded --exclude \'.git\' --exclude \'.sass-cache\'');
$dbApplication->setOption('packageMethod', 'git');
$dbApplication->setOption('updateMethod', NULL);
$dbApplication->setOption('branch', 'master');
$dbApplication->setDeploymentPath($deploymentPath);
$dbNode = new \TYPO3\Surf\Domain\Model\Node($dbHost);
$dbNode->setHostname($dbHostname);
$dbNode->setOption('username', $username);
$dbNode->setOption('port', $dbPort);
$dbApplication->addNode($dbNode);
$deployment->addApplication($dbApplication);
/**
* Create workflow
*/
$workflow = new \BGM\Deployment\Domain\Model\TYPO3CMSWorkflow();
$deployment->setWorkflow($workflow);
/**
* Compile CSS
*/
$compilecssOptions = array(
'command' => '
cd "{workspacePath}" &&
BUNDLE_GEMFILE=typo3conf/ext/bgm_theme_mymultiplenodes/Resources/Private/Gemfile bundle install &&
BUNDLE_GEMFILE=typo3conf/ext/bgm_theme_mymultiplenodes/Resources/Private/Gemfile bundle exec compass compile typo3conf/ext/bgm_theme_mymultiplenodes/Resources/Private/ --force',
);
$workflow->defineTask('my.multiplenodes.livedeployment:compilecss', 'typo3.surf:localshell', $compilecssOptions);
$workflow->afterStage('package', 'my.multiplenodes.livedeployment:compilecss');
/**
* Set release identifier file
*/
$setreleaseidentifierfileOptions = array(
'command' => '
echo ' . escapeshellarg('<?php echo \'' . $deployment->getReleaseIdentifier() . '\'; ?>') . ' > {releasePath}/Release_' . $deployment->getReleaseIdentifier() . '.php',
);
$workflow->defineTask('my.multiplenodes.livedeployment:setreleaseidentifierfile', 'typo3.surf:shell', $setreleaseidentifierfileOptions);
$workflow->afterStage('transfer', 'my.multiplenodes.livedeployment:setreleaseidentifierfile');
/**
* Set AdditionalConfiguration.php
*
* AdditionalConfiguration.php has to exist and has to contain at least "<?php if (!defined ('TYPO3_MODE')) die('Access denied.'); ?>"
*/
$setadditionalconfigurationOptions = array(
'command' => '
echo ' . escapeshellarg(\TYPO3\Flow\Utility\Files::getFileContents(FLOW_PATH_ROOT . 'Build/Surf/Resources/My.MultipleNodes.LiveDeployment/AdditionalConfiguration.php')) . ' > {releasePath}/typo3conf/AdditionalConfiguration.php',
);
$workflow->defineTask('my.multiplenodes.livedeployment:setadditionalconfiguration', 'typo3.surf:shell', $setadditionalconfigurationOptions);
$workflow->afterStage('transfer', 'my.multiplenodes.livedeployment:setadditionalconfiguration');
/**
* Set iniset.php
* iniset.php has to exist and has to contain at least "<?php ?>"
*/
$setinisetOptions = array(
'command' => '
echo ' . escapeshellarg(\TYPO3\Flow\Utility\Files::getFileContents(FLOW_PATH_ROOT . 'Build/Surf/Resources/My.MultipleNodes.LiveDeployment/iniset.php')) . ' > {releasePath}/typo3conf/iniset.php;
echo ' . escapeshellarg(\TYPO3\Flow\Utility\Files::getFileContents(FLOW_PATH_ROOT . 'Build/Surf/Resources/My.MultipleNodes.LiveDeployment/iniset.php')) . ' > {currentPath}/typo3conf/iniset.php',
'rollbackCommand' => '
rm -f {currentPath}/typo3conf/iniset.php',
);
$workflow->defineTask('my.multiplenodes.livedeployment:setiniset', 'typo3.surf:shell', $setinisetOptions);
$workflow->afterStage('transfer', 'my.multiplenodes.livedeployment:setiniset');
/**
* Set typo3conf/ext/bgm_theme_mymultiplenodes/Configuration/TsConfig/Page/Local.ts
* LocalPageTSconfig.ts has to exist
*/
$setlocalpagetsconfigOptions = array(
'command' => '
echo ' . escapeshellarg(\TYPO3\Flow\Utility\Files::getFileContents(FLOW_PATH_ROOT . 'Build/Surf/Resources/My.MultipleNodes.LiveDeployment/LocalPageTSconfig.ts')) . ' > {releasePath}/typo3conf/ext/bgm_theme_mymultiplenodes/Configuration/TsConfig/Page/Local.ts',
);
$workflow->defineTask('my.multiplenodes.livedeployment:setlocalpagetsconfig', 'typo3.surf:shell', $setlocalpagetsconfigOptions);
$workflow->afterStage('transfer', 'my.multiplenodes.livedeployment:setlocalpagetsconfig');
/**
* Set symlinks to typo3_src and shared files
*/
$setsymlinksOptions = array(
'command' => '
ln -s ' . $typo3srcPath . ' {releasePath}/typo3_src &&
ln -s ' . $filesPath . ' {releasePath}/files',
);
$workflow->defineTask('my.multiplenodes.livedeployment:setsymlinks', 'typo3.surf:shell', $setsymlinksOptions);
$workflow->afterStage('transfer', 'my.multiplenodes.livedeployment:setsymlinks');
/**
* Set backend lock on next live
*/
$setbackendlockOptions = array(
'command' => '
{releasePath}/typo3/cli_dispatch.phpsh lowlevel_admin setBElock;
{currentPath}/typo3/cli_dispatch.phpsh lowlevel_admin setBElock;
true',
'rollbackCommand' => '
{releasePath}/typo3/cli_dispatch.phpsh lowlevel_admin clearBElock;
{currentPath}/typo3/cli_dispatch.phpsh lowlevel_admin clearBElock;
true',
);
$workflow->defineTask('my.multiplenodes.livedeployment:setbackendlock', 'typo3.surf:shell', $setbackendlockOptions);
$workflow->beforeStage('migrate', 'my.multiplenodes.livedeployment:setbackendlock');
/**
* Do database backup
*/
$dodatabasebackupOptions = array(
'command' => '
mysqldump -u' . $dbconUsername . ' -p' . $dbconPassword . ' -h' . $dbconHost . ' -P' . $dbconPort . ' --default-character-set=utf8 --opt --skip-lock-tables --skip-add-locks --lock-tables=false --single-transaction --quick ' . $dbconDatabase . ' > {currentPath}/deploymentbackup.sql',
'rollbackCommand' => '
mysql -u' . $dbconUsername . ' -p' . $dbconPassword . ' -h' . $dbconHost . ' -P' . $dbconPort . ' ' . $dbconDatabase . ' < {currentPath}/deploymentbackup.sql &&
rm -f {currentPath}/deploymentbackup.sql;
true',
);
$workflow->defineTask('my.multiplenodes.livedeployment:dodatabasebackup', 'typo3.surf:shell', $dodatabasebackupOptions);
$workflow->beforeStage('migrate', 'my.multiplenodes.livedeployment:dodatabasebackup', $dbApplication);
/**
* Do database compare on next live
*
* 1=ACTION_UPDATE_CLEAR_TABLE ,2=ACTION_UPDATE_ADD ,3=ACTION_UPDATE_CHANGE ,4=ACTION_UPDATE_CREATE_TABLE ,5=ACTION_REMOVE_CHANGE ,6=ACTION_REMOVE_DROP ,7=ACTION_REMOVE_CHANGE_TABLE ,8=ACTION_REMOVE_DROP_TABLE
*
* @see EXT:coreapi/Classes/Service/DatabaseApiService.php
*/
$dodatabasecompareOptions = array(
'command' => '
sync;
{releasePath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearallactiveopcodecache;
{releasePath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearconfigurationcache;
{releasePath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearsystemcache;
{releasePath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearpagecache;
{releasePath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearallcaches;
{releasePath}/typo3/cli_dispatch.phpsh extbase databaseapi:databasecompare 2,3,4',
'rollbackCommand' => '
sync;
{currentPath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearallactiveopcodecache;
{currentPath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearconfigurationcache;
{currentPath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearsystemcache;
{currentPath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearpagecache;
{currentPath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearallcaches;
{currentPath}/typo3/cli_dispatch.phpsh extbase databaseapi:databasecompare 2,3,4',
);
$workflow->defineTask('my.multiplenodes.livedeployment:dodatabasecompare', 'typo3.surf:shell', $dodatabasecompareOptions);
$workflow->addTask('my.multiplenodes.livedeployment:dodatabasecompare', 'migrate', $dbApplication);
/**
* Symlink shared typo3temp in releasePath
*
* On rollback, reload apache2
*/
$copytempassetsOptions = array(
'command' => '
rm -rf {releasePath}/typo3temp;
ln -s {sharedPath}/typo3temp {releasePath}/typo3temp;
sync;
true',
'rollbackCommand' => '
sync;
sudo /etc/init.d/apache2 reload;
sudo /etc/init.d/nginx reload;
rm -rf {currentPath}/typo3temp/Cache;
rm -rf {currentPath}/typo3temp/locks;
true',
);
$workflow->defineTask('my.multiplenodes.livedeployment:copytempassets', 'typo3.surf:shell', $copytempassetsOptions);
$workflow->addTask('my.multiplenodes.livedeployment:copytempassets', 'finalize');
/**
* Reload Apache
*/
$reloadapacheOptions = array(
'command' => '
sync;
sudo /etc/init.d/apache2 reload;
sudo /etc/init.d/nginx reload;
rm -rf {currentPath}/typo3temp/Cache;
rm -rf {currentPath}/typo3temp/locks;
true',
);
$workflow->defineTask('my.multiplenodes.livedeployment:reloadapache', 'typo3.surf:shell', $reloadapacheOptions);
$workflow->afterStage('switch', 'my.multiplenodes.livedeployment:reloadapache');
/**
* Wait for symlink switch recognized by all caches
*/
$waitforsymlinkswitchOptions = array(
'command' => '
testcurl=$(curl -Is \'http://server1.multiplenodes.my.projects.localhost/Release_' . $deployment->getReleaseIdentifier() . '.php\' | head -n 1 | grep \'200\' | wc -l);
echo "testcurl $testcurl";
testcurl2=$(curl -Is \'http://server2.multiplenodes.my.projects.localhost/Release_' . $deployment->getReleaseIdentifier() . '.php\' | head -n 1 | grep \'200\' | wc -l);
echo "testcurl2 $testcurl2";
testcurl3=$(curl -Is \'http://server3.multiplenodes.my.projects.localhost/Release_' . $deployment->getReleaseIdentifier() . '.php\' | head -n 1 | grep \'200\' | wc -l);
echo "testcurl3 $testcurl3";
testcurl4=$(curl -Is \'http://server4.multiplenodes.my.projects.localhost/Release_' . $deployment->getReleaseIdentifier() . '.php\' | head -n 1 | grep \'200\' | wc -l);
echo "testcurl4 $testcurl4";
counter=0;
while [ $testcurl -ne 1 ] || [ $testcurl2 -ne 1 ];
do echo \'waitforsymlinkswitch\';
sleep 1;
testcurl=$(curl -Is \'http://server1.multiplenodes.my.projects.localhost/Release_' . $deployment->getReleaseIdentifier() . '.php\' | head -n 1 | grep \'200\' | wc -l);
echo "testcurl $testcurl";
testcurl2=$(curl -Is \'http://server2.multiplenodes.my.projects.localhost/Release_' . $deployment->getReleaseIdentifier() . '.php\' | head -n 1 | grep \'200\' | wc -l);
echo "testcurl2 $testcurl2";
testcurl3=$(curl -Is \'http://server3.multiplenodes.my.projects.localhost/Release_' . $deployment->getReleaseIdentifier() . '.php\' | head -n 1 | grep \'200\' | wc -l);
echo "testcurl3 $testcurl3";
testcurl4=$(curl -Is \'http://server4.multiplenodes.my.projects.localhost/Release_' . $deployment->getReleaseIdentifier() . '.php\' | head -n 1 | grep \'200\' | wc -l);
echo "testcurl4 $testcurl4";
counter=$(( counter+1 ));
echo "counter $counter";
done;',
);
$workflow->defineTask('my.multiplenodes.livedeployment:waitforsymlinkswitch', 'typo3.surf:shell', $waitforsymlinkswitchOptions);
$workflow->addTask('my.multiplenodes.livedeployment:waitforsymlinkswitch', 'warmup', $dbApplication);
/**
* Wait for symlink switch recognized by all caches
*/
$waitforsymlinkswitchexternalOptions = array(
'command' => '
testcurl=$(curl -Is \'https://www.multiplenodes.com/Release_' . $deployment->getReleaseIdentifier() . '.php\' | head -n 1 | grep \'200\' | wc -l);
echo "testcurl $testcurl";
counter=0;
while [ $testcurl -ne 1 ] || [ $testcurl2 -ne 1 ];
do echo \'waitforsymlinkswitch\';
sleep 1;
testcurl=$(curl -Is \'https://www.multiplenodes.com/Release_' . $deployment->getReleaseIdentifier() . '.php\' | head -n 1 | grep \'200\' | wc -l);
echo "testcurl $testcurl";
counter=$(( counter+1 ));
echo "counter $counter";
done;',
);
$workflow->defineTask('my.multiplenodes.livedeployment:waitforsymlinkswitchexternal', 'typo3.surf:localshell', $waitforsymlinkswitchexternalOptions);
$workflow->addTask('my.multiplenodes.livedeployment:waitforsymlinkswitchexternal', 'warmup', $dbApplication);
/**
* Clear all caches
*/
$clearallcachesafterswitchOptions = array(
'command' => '
{currentPath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearallactiveopcodecache;
{currentPath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearconfigurationcache;
{currentPath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearsystemcache;
{currentPath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearpagecache;
{currentPath}/typo3/cli_dispatch.phpsh extbase cacheapi:clearallcaches;
true;',
);
$workflow->defineTask('my.multiplenodes.livedeployment:clearallcachesafterswitch', 'typo3.surf:shell', $clearallcachesafterswitchOptions);
$workflow->addTask('my.multiplenodes.livedeployment:clearallcachesafterswitch', 'warmup', $dbApplication);
/**
* Remove backend locks
*/
$removebackendlockOptions = array(
'command' => '
{currentPath}/typo3/cli_dispatch.phpsh lowlevel_admin clearBElock;
{previousPath}/typo3/cli_dispatch.phpsh lowlevel_admin clearBElock;
true',
);
$workflow->defineTask('my.multiplenodes.livedeployment:removebackendlock', 'typo3.surf:shell', $removebackendlockOptions);
$workflow->beforeStage('cleanup', 'my.multiplenodes.livedeployment:removebackendlock');
/**
* Set git tag
*/
$settagOptions = array(
'tagName' => '{deploymentName}-{releaseIdentifier}',
'description' => 'Deployed with {deploymentName} at ' . date('Y-m-d H:i') . '
Release identifier is {releaseIdentifier}',
'pushTag' => TRUE,
);
$workflow->defineTask('my.multiplenodes.livedeployment:settag', 'bgm.deployment:git:tag', $settagOptions);
$workflow->beforeStage('cleanup', 'my.multiplenodes.livedeployment:settag', $dbApplication);
/**
* Remove iniset.php
*/
$removeinisetOptions = array(
'command' => '
rm -f {currentPath}/typo3conf/iniset.php;
rm -f {previousPath}/typo3conf/iniset.php;
true',
);
$workflow->defineTask('my.multiplenodes.livedeployment:removeiniset', 'typo3.surf:shell', $removeinisetOptions);
$workflow->addTask('my.multiplenodes.livedeployment:removeiniset', 'cleanup');
/**
* Compress database backup
*/
$compressdatabasebackupOptions = array(
'command' => '
gzip {previousPath}/deploymentbackup.sql;
true',
);
$workflow->defineTask('my.multiplenodes.livedeployment:compressdatabasebackup', 'typo3.surf:shell', $compressdatabasebackupOptions);
$workflow->addTask('my.multiplenodes.livedeployment:compressdatabasebackup', 'cleanup', $dbApplication);
/**
* Delete all releases older than 6 days, but keeps at least 5 releases
*/
$deleteoldreleasesOptions = array(
'command' => '
ls -At1 --ignore=previous --ignore=current --ignore=next {deploymentPath}/releases/ | tail -n +5 | xargs -n1 basename|xargs -n1 -I{} find {deploymentPath}/releases/ -name {} -type d -mtime +6 | xargs -r rm -rf;
true',
);
$workflow->defineTask('my.multiplenodes.livedeployment:deleteoldreleases', 'typo3.surf:shell', $deleteoldreleasesOptions);
$workflow->addTask('my.multiplenodes.livedeployment:deleteoldreleases', 'cleanup');
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment