/** * Executes this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @throws \TYPO3\Surf\Exception\TaskExecutionException * @throws \TYPO3\Surf\Exception\InvalidConfigurationException */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { $options['username'] = isset($options['username']) ? $options['username'] . '@' : ''; $targetReleasePath = $deployment->getApplicationReleasePath($application); $configurationPath = $deployment->getDeploymentConfigurationPath() . '/'; if (!is_dir($configurationPath)) { return; } $encryptedConfiguration = glob($configurationPath . '*.yaml.encrypted'); if (count($encryptedConfiguration) > 0) { throw new \TYPO3\Surf\Exception\TaskExecutionException('You have sealed configuration files, please open the configuration for "' . $deployment->getName() . '"', 1317229449); } $configurations = glob($configurationPath . '*.yaml'); $commands = array(); foreach ($configurations as $configuration) { $targetConfigurationPath = dirname(str_replace($configurationPath, '', $configuration)); if ($node->isLocalhost()) { $commands[] = "mkdir -p '{$targetReleasePath}/Configuration/{$targetConfigurationPath}/'"; $commands[] = "cp {$configuration} {$targetReleasePath}/Configuration/{$targetConfigurationPath}/"; } else { $username = $options['username']; $hostname = $node->getHostname(); $sshPort = $node->hasOption('port') ? '-p ' . escapeshellarg($node->getOption('port')) : ''; $scpPort = $node->hasOption('port') ? '-P ' . escapeshellarg($node->getOption('port')) : ''; $commands[] = "ssh {$sshPort} {$username}{$hostname} 'mkdir -p {$targetReleasePath}/Configuration/{$targetConfigurationPath}/'"; $commands[] = "scp {$scpPort} {$configuration} {$username}{$hostname}:{$targetReleasePath}/Configuration/{$targetConfigurationPath}/"; } } $localhost = new Node('localhost'); $localhost->setHostname('localhost'); $this->shell->executeOrSimulate($commands, $localhost, $deployment); }
/** * Executes this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @throws \TYPO3\Surf\Exception\TaskExecutionException * @throws \TYPO3\Surf\Exception\InvalidConfigurationException */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { $options['username'] = isset($options['username']) ? $options['username'] . '@' : ''; $targetReleasePath = $deployment->getApplicationReleasePath($application); $configurationPath = $deployment->getDeploymentConfigurationPath() . '/'; if (!is_dir($configurationPath)) { return; } $configurations = glob($configurationPath . '*'); $commands = array(); foreach ($configurations as $configuration) { $targetConfigurationPath = dirname(str_replace($configurationPath, '', $configuration)); if ($node->isLocalhost()) { $commands[] = "mkdir -p '{$targetReleasePath}/Configuration/{$targetConfigurationPath}/'"; $commands[] = "cp {$configuration} {$targetReleasePath}/Configuration/{$targetConfigurationPath}/"; } else { $username = $options['username']; $hostname = $node->getHostname(); $sshPort = $node->hasOption('port') ? '-p ' . escapeshellarg($node->getOption('port')) : ''; $scpPort = $node->hasOption('port') ? '-P ' . escapeshellarg($node->getOption('port')) : ''; $commands[] = "ssh {$sshPort} {$username}{$hostname} 'mkdir -p {$targetReleasePath}/Configuration/{$targetConfigurationPath}/'"; $commands[] = "scp {$scpPort} {$configuration} {$username}{$hostname}:{$targetReleasePath}/Configuration/{$targetConfigurationPath}/"; } } $localhost = new Node('localhost'); $localhost->setHostname('localhost'); $this->shell->executeOrSimulate($commands, $localhost, $deployment); }
/** * Execute this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @return void * @throws \TYPO3\Surf\Exception\InvalidConfigurationException */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { if (!$node->getOption('webBaseUrl')) { throw new \InvalidArgumentException('The webBaseUrl option must be set in all nodes for which the ClearOpcacheTask should be executed.'); } if (empty($options['deployutilsToken'])) { throw new \InvalidArgumentException('The deployutilsToken option is missing.'); } $url = rtrim($node->getOption('webBaseUrl'), '/') . '/typo3conf/ext/deployutils/Resources/Php/ClearOpcache.php?token='; $deployment->getLogger()->debug('Calling opcache clearing script at: ' . $url . 'xxx'); $url = $url . urlencode($options['deployutilsToken']); $result = $this->executeLocalCurlRequest($url, 5); $this->assertExpectedStatus(['expectedStatus' => 200], $result); $this->assertExpectedRegexp(['expectedRegexp' => '/success/'], $result); }
/** * Execute this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @throws \TYPO3\Surf\Exception\InvalidConfigurationException * @return void */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { $this->assertRequiredOptionsExist($options); $dumpCommand = new ProcessBuilder(); $dumpCommand->setPrefix('mysqldump'); $dumpCommand->setArguments(array('-h', $options['sourceHost'], '-u', $options['sourceUser'], '-p' . $options['sourcePassword'], $options['sourceDatabase'])); $mysqlCommand = new ProcessBuilder(); $mysqlCommand->setPrefix('mysql'); $mysqlCommand->setArguments(array('-h', $options['targetHost'], '-u', $options['targetUser'], '-p' . $options['targetPassword'], $options['targetDatabase'])); $arguments = array(); $username = isset($options['username']) ? $options['username'] . '@' : ''; $hostname = $node->getHostname(); $arguments[] = $username . $hostname; if ($node->hasOption('port')) { $arguments[] = '-P'; $arguments[] = $node->getOption('port'); } $arguments[] = $mysqlCommand->getProcess()->getCommandLine(); $sshCommand = new ProcessBuilder(); $sshCommand->setPrefix('ssh'); $sshCommand->setArguments($arguments); $command = $dumpCommand->getProcess()->getCommandLine() . ' | ' . $sshCommand->getProcess()->getCommandLine(); $localhost = new Node('localhost'); $localhost->setHostname('localhost'); $this->shell->executeOrSimulate($command, $localhost, $deployment); }
/** * Executes this task * * Options: * command: The command to execute * rollbackCommand: The command to execute as a rollback (optional) * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @return void * @throws \TYPO3\Surf\Exception\InvalidConfigurationException */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { if (!isset($options['folders'])) { return; } $folders = $options['folders']; if (!is_array($folders)) { $folders = array($folders); } $replacePaths = array('{deploymentPath}' => escapeshellarg($application->getDeploymentPath()), '{sharedPath}' => escapeshellarg($application->getSharedPath()), '{releasePath}' => escapeshellarg($deployment->getApplicationReleasePath($application)), '{currentPath}' => escapeshellarg($application->getReleasesPath() . '/current'), '{previousPath}' => escapeshellarg($application->getReleasesPath() . '/previous')); $commands = array(); $username = isset($options['username']) ? $options['username'] . '@' : ''; $hostname = $node->getHostname(); $port = $node->hasOption('port') ? '-P ' . escapeshellarg($node->getOption('port')) : ''; foreach ($folders as $folderPair) { if (!is_array($folderPair) || count($folderPair) !== 2) { throw new InvalidConfigurationException('Each rsync folder definition must be an array of exactly two folders', 1405599056); } $sourceFolder = rtrim(str_replace(array_keys($replacePaths), $replacePaths, $folderPair[0]), '/') . '/'; $targetFolder = rtrim(str_replace(array_keys($replacePaths), $replacePaths, $folderPair[1]), '/') . '/'; $commands[] = "rsync -avz --delete -e ssh {$sourceFolder} {$username}{$hostname}:{$targetFolder}"; } $ignoreErrors = isset($options['ignoreErrors']) && $options['ignoreErrors'] === true; $logOutput = !(isset($options['logOutput']) && $options['logOutput'] === false); $localhost = new Node('localhost'); $localhost->setHostname('localhost'); $this->shell->executeOrSimulate($commands, $localhost, $deployment, $ignoreErrors, $logOutput); }
/** * Executes this task * * @param Node $node * @param Application $application * @param Deployment $deployment * @param array $options * @throws TaskExecutionException * @return void */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { if ($node->isLocalhost()) { $deployment->getLogger()->log('node seems not to be a remote node', LOG_DEBUG); } else { $username = $node->hasOption('username') ? $node->getOption('username') : NULL; if (!empty($username)) { $username = $username . '@'; } $hostname = $node->getHostname(); $sshOptions = array('-A', '-q', '-o BatchMode=yes'); if ($node->hasOption('port')) { $sshOptions[] = '-p ' . escapeshellarg($node->getOption('port')); } $command = 'ssh ' . implode(' ', $sshOptions) . ' ' . escapeshellarg($username . $hostname) . ' exit;'; $this->shell->execute($command, $deployment->getNode('localhost'), $deployment); $deployment->getLogger()->log('SSH connection successfully established', LOG_DEBUG); } }
/** * Execute this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @throws InvalidConfigurationException * @return void */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { $this->assertRequiredOptionsExist($options); $username = isset($options['username']) ? $options['username'] . '@' : ''; $hostname = $node->getHostname(); $port = $node->hasOption('port') ? '-P ' . escapeshellarg($node->getOption('port')) : ''; $commands[] = "mysqldump -h {$options['sourceHost']} -u{$options['sourceUser']} -p{$options['sourcePassword']} {$options['sourceDatabase']} | ssh {$port} {$username}{$hostname} 'mysql -h {$options['targetHost']} -u{$options['targetUser']} -p{$options['targetPassword']} {$options['targetDatabase']}'"; $localhost = new Node('localhost'); $localhost->setHostname('localhost'); $this->shell->executeOrSimulate($commands, $localhost, $deployment); }
/** * @param Node $node * @param string $file * @return string */ protected function getArgument(Node $node, $file) { if ($node->isLocalhost() === TRUE) { return $file; } $argument = ''; if ($node->hasOption('port')) { $port = $node->getOption('port'); if (!empty($port)) { $argument .= '-P ' . $port . ' '; } } if ($node->hasOption('username')) { $username = $node->getOption('username'); if (!empty($username)) { $argument .= $username . '@'; } } $argument .= $node->getHostname() . ':'; $argument .= $file; return $argument; }
/** * @param Node $node * @param Application $application * @param string $path * @param string $file * @return string */ protected function getArgument(Node $node, Application $application, $path, $file) { $argument = ''; if ($node->hasOption('username')) { $username = $node->getOption('username'); if (!empty($username)) { $argument .= $username . '@'; } } $argument .= $node->getHostname() . ':'; $argument .= rtrim($application->getReleasesPath(), '/') . '/'; $argument = rtrim($argument . $path, '/') . '/'; $argument .= $file; return $argument; }
/** * Execute a shell command via SSH * * @param mixed $command * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param bool $logOutput TRUE if the output of the command should be logged * @return array */ protected function executeRemoteCommand($command, Node $node, Deployment $deployment, $logOutput = true) { $command = $this->prepareCommand($command); $deployment->getLogger()->debug('$' . $node->getName() . ': "' . $command . '"'); if ($node->hasOption('remoteCommandExecutionHandler')) { $remoteCommandExecutionHandler = $node->getOption('remoteCommandExecutionHandler'); /** @var $remoteCommandExecutionHandler callable */ return $remoteCommandExecutionHandler($this, $command, $node, $deployment, $logOutput); } $username = $node->hasOption('username') ? $node->getOption('username') : null; if (!empty($username)) { $username = $username . '@'; } $hostname = $node->getHostname(); // TODO Get SSH options from node or deployment $sshOptions = array('-A'); if ($node->hasOption('port')) { $sshOptions[] = '-p ' . escapeshellarg($node->getOption('port')); } if ($node->hasOption('password')) { $sshOptions[] = '-o PubkeyAuthentication=no'; } if ($node->hasOption('privateKeyFile')) { $sshOptions[] = '-i ' . escapeshellarg($node->getOption('privateKeyFile')); } $sshCommand = 'ssh ' . implode(' ', $sshOptions) . ' ' . escapeshellarg($username . $hostname) . ' ' . escapeshellarg($command); if ($node->hasOption('password')) { $passwordSshLoginScriptPathAndFilename = Files::concatenatePaths(array(dirname(dirname(dirname(__DIR__))), 'Resources', 'Private/Scripts/PasswordSshLogin.expect')); if (\Phar::running() !== '') { $passwordSshLoginScriptContents = file_get_contents($passwordSshLoginScriptPathAndFilename); $passwordSshLoginScriptPathAndFilename = Files::concatenatePaths(array($deployment->getTemporaryPath(), 'PasswordSshLogin.expect')); file_put_contents($passwordSshLoginScriptPathAndFilename, $passwordSshLoginScriptContents); } $sshCommand = sprintf('expect %s %s %s', escapeshellarg($passwordSshLoginScriptPathAndFilename), escapeshellarg($node->getOption('password')), $sshCommand); } $success = $this->executeProcess($deployment, $sshCommand, $logOutput, ' > '); if (isset($passwordSshLoginScriptPathAndFilename) && \Phar::running() !== '') { unlink($passwordSshLoginScriptPathAndFilename); } return $success; }
/** * Execute a shell command via SSH * * @param mixed $command * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param bool $logOutput TRUE if the output of the command should be logged * @return array */ protected function executeRemoteCommand($command, Node $node, Deployment $deployment, $logOutput = true) { $command = $this->prepareCommand($command); $deployment->getLogger()->debug('$' . $node->getName() . ': "' . $command . '"'); if ($node->hasOption('remoteCommandExecutionHandler')) { $remoteCommandExecutionHandler = $node->getOption('remoteCommandExecutionHandler'); /** @var $remoteCommandExecutionHandler callable */ return $remoteCommandExecutionHandler($this, $command, $node, $deployment, $logOutput); } $username = $node->hasOption('username') ? $node->getOption('username') : null; if (!empty($username)) { $username = $username . '@'; } $hostname = $node->getHostname(); // TODO Get SSH options from node or deployment $sshOptions = array('-A'); if ($node->hasOption('port')) { $sshOptions[] = '-p ' . escapeshellarg($node->getOption('port')); } if ($node->hasOption('password')) { $sshOptions[] = '-o PubkeyAuthentication=no'; } if ($node->hasOption('privateKeyFile')) { $sshOptions[] = '-i ' . escapeshellarg($node->getOption('privateKeyFile')); } $sshCommand = 'ssh ' . implode(' ', $sshOptions) . ' ' . escapeshellarg($username . $hostname) . ' ' . escapeshellarg($command); if ($node->hasOption('password')) { $resourcesPath = realpath(__DIR__ . '/../../../Resources'); $passwordSshLoginScriptPathAndFilename = $resourcesPath . '/Private/Scripts/PasswordSshLogin.expect'; $sshCommand = sprintf('expect %s %s %s', escapeshellarg($passwordSshLoginScriptPathAndFilename), escapeshellarg($node->getOption('password')), $sshCommand); } return $this->executeProcess($deployment, $sshCommand, $logOutput, ' > '); }
/** * @param Node $node * @param Deployment $deployment * @param array $options * @param Application $application * @return string * @throws InvalidConfigurationException * @throws TaskExecutionException */ protected function getSharedPathFromNode(Node $node, Deployment $deployment, $options, Application $application) { if ($node->hasOption('sharedPath')) { $sharedPath = $node->getOption('sharedPath'); } else { if ($node->hasOption('deploymentPath')) { $deploymentPath = $node->getOption('deploymentPath'); } elseif (!empty($options['deploymentPath'])) { $deploymentPath = $options['deploymentPath']; } else { throw new InvalidConfigurationException('No deploymentPath defined!', 1414849872); } $webDir = $this->getWebDir($deployment, $application); if ($webDir !== '') { $deploymentPath = rtrim($deploymentPath, '/') . '/' . $webDir; } $commands = array(); $commands[] = 'cd ' . escapeshellarg($deploymentPath); $commands[] = 'readlink ' . escapeshellarg('fileadmin'); $output = $this->shell->execute($commands, $node, $deployment, TRUE); if (preg_match('/(.+)\\/fileadmin\\/?$/', trim($output), $matches)) { $sharedPath = $matches[1]; } else { $sharedPath = str_replace('htdocs', 'shared', $deploymentPath); } } if ($sharedPath[0] !== '/') { $sharedPath = rtrim($deploymentPath, '/') . '/' . $sharedPath; } return rtrim($sharedPath, '/') . '/'; }
/** * @param string $localPath * @param string $remotePath */ protected function upload($localPath, $remotePath) { $cmd = sprintf('rsync -e "ssh -p %d" -avz %s %s@%s:%s', $this->remoteNode->getOption('port'), $localPath, $this->remoteNode->getOption('username'), $this->remoteNode->getHostname(), $remotePath); $this->log('Uploading files to remote instance'); $this->shell->executeOrSimulate($cmd, $this->localNode, $this->deployment); }
/** * @param Node $node * @param string $path * @return string */ protected function getFullPath(Node $node, $path) { $hostArgument = ''; if ($node->isLocalhost() === FALSE) { if ($node->hasOption('username')) { $hostArgument .= $node->getOption('username') . '@'; } $hostArgument .= $node->getHostname() . ':'; } return escapeshellarg($hostArgument . rtrim($path, '/') . '/'); }