DeployDevController.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. <?php
  2. namespace application\controllers;
  3. class DeployDevController {
  4. public static function deploy($data): void {
  5. $username = $data['username'];
  6. $domain = $data['domain'];
  7. $adminName = $data['admin_name'] ?? '';
  8. $adminPassword = $data['admin_password'];
  9. $databaseName = $username . "_dev_";
  10. $databaseName = $databaseName . str_replace(['-', '.'], ["_", "_"], $domain);
  11. $webDir = "/home/$username/dev.$domain";
  12. $configTemplate = '/etc/apache2/site-config.in';
  13. $configFile = "/etc/apache2/sites-enabled/dev.$domain.conf";
  14. if (empty($username) || empty($domain) || empty($adminName) || empty($adminPassword)) {
  15. error_log("deploy: ERROR: No username, domain, admin_name or admin_password provided");
  16. http_response_code(400);
  17. error_log("deploy: ERROR: UserName 1 " . $username);
  18. error_log("deploy: ERROR: Domain 1 " . $domain);
  19. error_log("deploy: ERROR: UserName 2 " . $data['username'] );
  20. error_log("deploy: ERROR: Domain 2 " . $data['domain'] );
  21. error_log("deploy: ERROR: AdminName " . $adminName);
  22. error_log("deploy: ERROR: AdminPasswd" . $adminPassword);
  23. error_log(print_r($data,true));
  24. echo json_encode(['error' => 'Missing required parameters']);
  25. return;
  26. }
  27. error_log(" Starting function deploy for " . $username . " and " . $domain . " DebugMode: " . $GLOBALS['debug']);
  28. $userExisted = false;
  29. if( strpos(file_get_contents("/etc/passwd"),$username) !== false) {
  30. $userExisted = true;
  31. }
  32. if ($userExisted != true) {
  33. // Create user without login access
  34. if ($GLOBALS['debug'] == true) {error_log("Adding User: " . $username); }
  35. exec("sudo /usr/sbin/useradd -m -k -M -s /usr/sbin/nologin $username 2>&1", $userOutput, $userReturnCode);
  36. if ($userReturnCode !== 0) {
  37. error_log("deploy: ERROR: Useradd for $username failed, details => " . implode("\n", $userOutput));
  38. http_response_code(500);
  39. echo json_encode(['error' => 'Failed to create user', 'details' => implode("\n", $userOutput)]);
  40. return;
  41. }
  42. }
  43. if ($GLOBALS['debug'] == true) { error_log("Creating Webdir ($webDir) for : " . $username); }
  44. exec("sudo /usr/bin/mkdir -p $webDir 2>&1", $mkdirOutput, $mkdirReturnCode);
  45. if ($mkdirReturnCode !== 0) {
  46. error_log("deploy: ERROR: Create Webdir for $username failed, details => ". implode("\n", $mkdirOutput));
  47. http_response_code(500);
  48. echo json_encode(['error' => 'Failed to create web dir', 'details' => implode("\n", $mkdirOutput)]);
  49. return;
  50. }
  51. if ($GLOBALS['debug'] == true) { error_log("Creating logdir for : " . $username); }
  52. if (is_dir("/home/$username/logs") != true) {
  53. exec("sudo /usr/bin/mkdir /home/$username/logs 2>&1", $mkdirOutput, $mkdirReturnCode);
  54. if ($mkdirReturnCode !== 0) {
  55. error_log("deploy: ERROR: Failed to create log directory for $username failed, details => " . implode("\n", $mkdirOutput));
  56. http_response_code(500);
  57. echo json_encode(['error' => 'Failed to create logs dir', 'details' => implode("\n", $mkdirOutput)]);
  58. return;
  59. }
  60. }
  61. if ($GLOBALS['debug'] == true) { error_log("Creating backup dir for : " . $username); }
  62. if (is_dir("/home/$username/backups") != true) {
  63. exec("sudo /usr/bin/mkdir /home/$username/backups 2>&1", $mkdirOutput, $mkdirReturnCode);
  64. if ($mkdirReturnCode !== 0) {
  65. error_log("deploy: ERROR: mkdir /home/$username/backups failed, details => " . implode("\n", $mkdirOutput));
  66. http_response_code(500);
  67. echo json_encode(['error' => 'Failed to create backups dir', 'details' => implode("\n", $mkdirOutput)]);
  68. return;
  69. }
  70. }
  71. if ($GLOBALS['debug'] == true) { error_log("Chown homedir: " . $username); }
  72. exec("sudo /usr/bin/chown $username:$username /home/$username -R 2>&1", $chownOutput, $chownReturnCode);
  73. if ($chownReturnCode !== 0) {
  74. error_log("deploy: ERROR: chown on /home/$username failed, details => " . implode("\n", $chownOutput));
  75. http_response_code(500);
  76. echo json_encode(['error' => 'Failed to chown backups dir', 'details' => implode("\n", $chownOutput)]);
  77. return;
  78. }
  79. if ($GLOBALS['debug'] == true) { error_log("Reading Apache Config Template /etc/apache2/site-config.in"); }
  80. $configContent = file_get_contents($configTemplate);
  81. if ($GLOBALS['debug'] == true) { error_log("Replace config settings in Apache Config Template"); }
  82. $configContent = str_replace(['DOCUMENTROOT', 'SERVERNAME','USERNAME', 'DOMAINNAME', 'SERVERALIAS'], [$webDir, "dev.$domain",$username,"dev.$domain", "" ], $configContent);
  83. if ($GLOBALS['debug'] == true) { error_log("Running Certbot for Domain " . $domain); }
  84. exec("sudo /usr/bin/certbot certonly --webroot -w /etc/apache2/letsencrypt -d dev.$domain --non-interactive --agree-tos --email admin@$domain 2>&1", $output, $returnCode);
  85. if ($returnCode !== 0) {
  86. error_log("deploy: ERROR: certbot failed to create certificate on dev.$domain, details => " . implode("\n", $output));
  87. http_response_code(500);
  88. echo json_encode(['error' => 'Certbot failed', 'details' => implode("\n", $output)]);
  89. return;
  90. }
  91. if ($GLOBALS['debug'] == true) { error_log("Replace sslsettings in in Apache Config Template"); }
  92. $configContent = str_replace('DOMAINNAME', $domain, $configContent);
  93. if ($GLOBALS['debug'] == true) { error_log("Writing apache config file to " . $configFile); }
  94. if (file_put_contents($configFile, $configContent) != true) {
  95. error_log("deploy: ERROR: while writing apache config");
  96. echo json_encode(['error' => 'Failed to write Apache config', 'details' => []]);
  97. }
  98. exec('sudo /usr/bin/systemctl reload apache2 2>&1', $apacheOutput, $apacheReturnCode);
  99. if ($GLOBALS['debug'] == true) { error_log("Restarting Apache"); }
  100. if ($apacheReturnCode !== 0) {
  101. error_log("deploy: ERROR: Apache Reload error, details => " . implode("\n", $apacheOutput));
  102. http_response_code(500);
  103. echo json_encode(['error' => 'Failed to reload Apache', 'details' => implode("\n", $apacheOutput)]);
  104. return;
  105. }
  106. // Create PHP-FPM User
  107. // /etc/php/8.2/fpm/user.in
  108. if ($userExisted != true) {
  109. if ($GLOBALS['debug'] == true) {error_log("Writing PHP-FPM Config for : " . $username); }
  110. $phpContent = file_get_contents("/etc/php/8.2/fpm/user.in");
  111. $phpContent = str_replace("USERNAME", $username, $phpContent);
  112. file_put_contents("/etc/php/8.2/fpm/pool.d/" . $username . ".conf", $phpContent);
  113. if ($GLOBALS['debug'] == true) {error_log("Restarting PHP-FPM : " . $username);}
  114. exec('sudo /usr/bin/systemctl reload php8.2-fpm', $phpOutput, $phpReturnCode);
  115. if ($phpReturnCode !== 0) {
  116. error_log("deploy: ERROR: PHP-FPM reload error, details => " . implode("\n", $phpOutput));
  117. http_response_code(500);
  118. echo json_encode(['error' => 'Failed to reload PHP-FPM', 'details' => implode("\n", $phpOutput)]);
  119. return;
  120. }
  121. }
  122. //Create MySQL Database
  123. if ($GLOBALS['debug'] == true) { error_log("creating database: " . $databaseName); }
  124. $sqlCommand = "sudo mysql -e \"create database $databaseName;\" 2>&1";
  125. exec($sqlCommand,$mysqlOutput,$mysqlReturnCode);
  126. if ($mysqlReturnCode !== 0) {
  127. error_log("deploy: MySQL create database error, details => " . implode("\n", $mysqlOutput));
  128. http_response_code(500);
  129. echo json_encode(['error' => 'Failed to create database $databaseName', 'details' => implode("\n", $mysqlOutput)]);
  130. return;
  131. }
  132. //Create MySQL User
  133. $sqlCommand = "sudo mysql -e \"create user '" . $username . "'@'localhost' identified by '" . $username . "'\" 2>&1";
  134. if ($GLOBALS['debug'] == true) { error_log("creating database user: " . $sqlCommand); }
  135. exec($sqlCommand,$mysqlOutput,$mysqlReturnCode);
  136. if ($mysqlReturnCode !== 0) {
  137. error_log("deploy: MySQL create user $username error, details => " . implode("\n", $mysqlOutput));
  138. http_response_code(500);
  139. echo json_encode(['error' => 'Failed to create databaseuser $username', 'details' => implode("\n", $mysqlOutput)]);
  140. return;
  141. }
  142. //Grant permission
  143. if ($GLOBALS['debug'] == true) { error_log("granting permission on $databaseName to: " . $username); }
  144. $sqlCommand = "sudo mysql -e \"grant all on " . $databaseName . ".* to '" . $username . "'@'localhost';\" 2>&1";
  145. exec($sqlCommand,$mysqlOutput,$mysqlReturnCode);
  146. if ($mysqlReturnCode !== 0) {
  147. error_log("deploy: MySQL grant permission to user $username error, details => " . implode("\n", $mysqlOutput));
  148. http_response_code(500);
  149. echo json_encode(['error' => 'Failed to grant permission on $databaseName ot $username', 'details' => implode("\n", $mysqlOutput)]);
  150. return;
  151. }
  152. /*
  153. // Deployment of the Concrete CMS Application
  154. if ($GLOBALS['debug'] == true) { error_log("Copy master directory to $webDir"); }
  155. exec("sudo /usr/bin/cp -r /var/www/master/* $webDir 2>&1",$cpOutput,$cpReturnCode);
  156. if ($cpReturnCode !== 0) {
  157. error_log("deploy: Error while copying master installation to $webDir, details => " . implode("\n", $cpOutput));
  158. http_response_code(500);
  159. echo json_encode(['error' => 'Failed to copy master installation into web dir', 'details' => implode("\n", $cpOutput)]);
  160. return;
  161. }
  162. if ($GLOBALS['debug'] == true) { error_log("Chown WebDir $webDir"); }
  163. exec("sudo /usr/bin/chown $username:$username $webDir -R 2>&1", $chownOutput, $chownReturnCode);
  164. if ($chownReturnCode !== 0) {
  165. error_log("deploy: chown error on $webDir, details => " . implode("\n", $chownOutput));
  166. http_response_code(500);
  167. echo json_encode(['error' => 'Failed to chown web dir', 'details' => implode("\n", $chownOutput)]);
  168. return;
  169. }
  170. if ($GLOBALS['debug'] == true) { error_log("Writing install script to: /home/" . $username . "/" . $databaseName ."-inst.sh"); }
  171. $installCommand = "#!/bin/bash\n";
  172. $installCommand .= "$webDir/concrete/bin/concrete5 c5:install --starting-point=restaurantly --db-server='localhost' --db-username='" . $username . "' --db-password='" . $username ."' --db-database='" . $databaseName . "' --timezone='Europe/Zurich' --admin-email='" . $adminName . "' --admin-password='" . $adminPassword . "' --site-locale=ch_DE --language=ch_DE --site='" . $domain . "' -n 2>&1 \n";
  173. $installCommand .= "$webDir/concrete/bin/concrete5 c5:package-install studio_templates 2>&1 \n";
  174. $installCommand .= "$webDir/concrete/bin/concrete5 studio:setup 2>&1 \n";
  175. file_put_contents("/var/www/scripts/" . $databaseName ."-inst.sh",$installCommand);
  176. if ($GLOBALS['debug'] == true) { error_log("Chmod install script: /home/" . $username . "/" . $databaseName ." -inst.sh"); }
  177. exec("sudo /usr/bin/chmod a+x /var/www/scripts/" . $databaseName ."-inst.sh 2>&1", $chmodOutput, $chmodReturnCode);
  178. if ($chmodReturnCode !== 0) {
  179. error_log("deploy: ERROR: chmod on /var/www/scripts/" . $databaseName ."-inst.sh failed, details => " . implode("\n", $chmodOutput));
  180. http_response_code(500);
  181. echo json_encode(['error' => 'Failed to chmod on /var/www/scripts/' . $databaseName .'-inst.sh', 'details' => implode("\n", $chmodOutput)]);
  182. return;
  183. }
  184. if ($GLOBALS['debug'] == true) { error_log("Executing Concrete 5 installation: " . $installCommand); }
  185. exec("sudo -u $username /var/www/sudo-concrete5.sh /var/www/scripts/" . $databaseName ."-inst.sh",$createOutput, $createReturnCode);
  186. if ($createReturnCode !== 0) {
  187. error_log("deploy: cms installation error, details => " . implode("\n", $createOutput));
  188. http_response_code(500);
  189. echo json_encode(['error' => 'Failed to install cms system', 'details' => implode("\n", $createOutput)]);
  190. return;
  191. }
  192. */
  193. echo json_encode(['success' => 'Development site deployed successfully','details' => implode("\n", $createOutput)]);
  194. }
  195. //exec("php /path/to/scripts/post_install_setup.php", $output, $code);
  196. public static function revert($data): void {
  197. $username = $data['username'] ?? '';
  198. $domain = $data['domain'] ?? '';
  199. $adminName = $data['admin_name'] ?? '';
  200. $adminPassword = $data['admin_password'] ?? '';
  201. $webDir = "/home/$username/dev.$domain";
  202. $databaseName = $username . "_dev_";
  203. $databaseName = $databaseName . str_replace(['-', '.'], ["_", "_"], $domain);
  204. exec("sudo /usr/bin/rm -rf $webDir 2>&1", $rmOutput, $rmReturnCode);
  205. if ($rmReturnCode !== 0) {
  206. error_log("revert: error on rm $webDir -r, details => " . implode("\n", $rmOutput));
  207. http_response_code(500);
  208. echo json_encode(['error' => 'Failed to remove webdir dir', 'details' => implode("\n", $rmOutput)]);
  209. return;
  210. }
  211. exec("sudo /usr/bin/mkdir $webDir 2>&1", $mkdirOutput, $mkdirReturnCode);
  212. error_log("revert: error on mkdir $webDir, details => " . implode("\n", $mkdirOutput));
  213. if ($mkdirReturnCode !== 0) {
  214. http_response_code(500);
  215. echo json_encode(['error' => 'Failed to create web dir', 'details' => implode("\n", $mkdirOutput)]);
  216. return;
  217. }
  218. exec("sudo /usr/bin/chown $username:$username $webDir 2>&1", $chownOutput, $chownReturnCode);
  219. if ($chownReturnCode !== 0) {
  220. error_log("revert: chown error on $webDir, details => " . implode("\n", $chownOutput));
  221. http_response_code(500);
  222. echo json_encode(['error' => 'Failed to chown web dir', 'details' => implode("\n", $chownOutput)]);
  223. return;
  224. }
  225. $sqlCommand = "sudo mysql \"drop database $databaseName;\" 2>&1";
  226. exec($sqlCommand,$mysqlOutput,$mysqlReturnCode);
  227. if ($mysqlReturnCode !== 0) {
  228. error_log("revert: MySQL drop database error, details => " . implode("\n", $mysqlOutput));
  229. http_response_code(500);
  230. echo json_encode(['error' => 'Failed to drop database $usernmae', 'details' => implode("\n", $mysqlOutput)]);
  231. return;
  232. }
  233. $sqlCommand = "sudo mysql \"create database $databaseName;\" 2>&1";
  234. exec($sqlCommand,$mysqlOutput,$mysqlReturnCode);
  235. if ($mysqlReturnCode !== 0) {
  236. error_log("revert: MySQL create database error, details => " . implode("\n", $mysqlOutput));
  237. http_response_code(500);
  238. echo json_encode(['error' => 'Failed to create database $usernmae', 'details' => implode("\n", $mysqlOutput)]);
  239. return;
  240. }
  241. // Deployment of the Concrete CMS Application
  242. exec("sudo /usr/bin/cp -r /var/www/master/* $webDir 2>&1",$cpOutput,$cpReturnCode);
  243. if ($cpReturnCode !== 0) {
  244. error_log("revert: Error while copying master installation to $webDir, details => " . implode("\n", $cpOutput));
  245. http_response_code(500);
  246. echo json_encode(['error' => 'Failed to copy master installation into web dir', 'details' => implode("\n", $cpOutput)]);
  247. return;
  248. }
  249. exec("sudo /usr/bin/chown $username:$username $webDir -R 2>&1", $chownOutput, $chownReturnCode);
  250. if ($chownReturnCode !== 0) {
  251. error_log("revert: chown error on $webDir, details => " . implode("\n", $chownOutput));
  252. http_response_code(500);
  253. echo json_encode(['error' => 'Failed to chown web dir', 'details' => implode("\n", $chownOutput)]);
  254. return;
  255. }
  256. exec("sudo -u $username /var/www/sudo-concrete5.sh $webDir/concrete/bin/concrete5 c5:install --db-server=localhost --db-username=$username --db-password=$username --db-database=$databaseName --timezone=\"Europe/Zurich\" --admin-email=$adminName --admin-password=$adminPassword --site-locale=ch_DE --language=ch_DE --site=$domain --starting-point=atomik_blank -n -vv 2>&1",$createOutput, $createReturnCode);
  257. if ($createReturnCode !== 0) {
  258. error_log("revert: cms installation error, details => " . implode("\n", $createOutput));
  259. http_response_code(500);
  260. echo json_encode(['error' => 'Failed to install cms system', 'details' => implode("\n", $createOutput)]);
  261. return;
  262. }
  263. exec("sudo /usr/bin/chown $username:$username $webDir 2>&1", $chownOutput, $chownReturnCode);
  264. if ($chownReturnCode !== 0) {
  265. error_log("revert: chown error on $webDir, details => " . implode("\n", $chownOutput));
  266. http_response_code(500);
  267. echo json_encode(['error' => 'Failed to chown web dir', 'details' => implode("\n", $chownOutput)]);
  268. return;
  269. }
  270. echo json_encode(['success' => 'Development site deployed successfully']);
  271. }
  272. public static function terminate($data): void {
  273. }
  274. }