AirtimeInstall.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. <?php
  2. set_include_path(__DIR__.'/../../airtime_mvc/library' . PATH_SEPARATOR . get_include_path());
  3. //Zend framework
  4. if (file_exists('/usr/share/php/libzend-framework-php')){
  5. set_include_path('/usr/share/php/libzend-framework-php' . PATH_SEPARATOR . get_include_path());
  6. }
  7. #require_once('Zend/Loader/Autoloader.php');
  8. class AirtimeInstall
  9. {
  10. const CONF_DIR_BINARIES = "/usr/lib/airtime";
  11. const CONF_DIR_WWW = "/usr/share/airtime";
  12. const CONF_DIR_LOG = "/var/log/airtime";
  13. public static $databaseTablesCreated = false;
  14. public static function GetAirtimeSrcDir()
  15. {
  16. return __DIR__."/../../..";
  17. }
  18. public static function GetUtilsSrcDir()
  19. {
  20. return __DIR__."/../../../../utils";
  21. }
  22. /**
  23. * Ensures that the user is running this PHP script with root
  24. * permissions. If not running with root permissions, causes the
  25. * script to exit.
  26. */
  27. public static function ExitIfNotRoot()
  28. {
  29. // Need to check that we are superuser before running this.
  30. if(posix_geteuid() != 0){
  31. echo "Must be root user.\n";
  32. exit(1);
  33. }
  34. }
  35. /**
  36. * Return the version of Airtime currently installed.
  37. * If not installed, return null.
  38. *
  39. * @return NULL|string
  40. */
  41. public static function GetVersionInstalled()
  42. {
  43. try {
  44. $con = Propel::getConnection();
  45. } catch (PropelException $e) {
  46. return null;
  47. }
  48. if (file_exists('/etc/airtime/airtime.conf')) {
  49. $values = parse_ini_file('/etc/airtime/airtime.conf', true);
  50. }
  51. else {
  52. return null;
  53. }
  54. $sql = "SELECT valstr FROM cc_pref WHERE keystr = 'system_version' LIMIT 1";
  55. try {
  56. $version = $con->query($sql)->fetchColumn(0);
  57. } catch (PDOException $e){
  58. // no pref table therefore Airtime is not installed.
  59. //We only get here if airtime database exists, but the table doesn't
  60. //This state sometimes happens if a previous Airtime uninstall couldn't remove
  61. //the database because it was busy, so it just removed the tables instead.
  62. return null;
  63. }
  64. //if version is empty string, then version is older than version 1.8.0
  65. if ($version == '') {
  66. try {
  67. // If this table exists, then it's version 1.7.0
  68. $sql = "SELECT * FROM cc_show_rebroadcast LIMIT 1";
  69. $result = $con->query($sql)->fetchColumn(0);
  70. $version = "1.7.0";
  71. } catch (Exception $e) {
  72. $version = null;
  73. }
  74. }
  75. return $version;
  76. }
  77. public static function DbTableExists($p_name)
  78. {
  79. $con = Propel::getConnection();
  80. try {
  81. $sql = "SELECT * FROM ".$p_name." LIMIT 1";
  82. $con->query($sql);
  83. } catch (PDOException $e){
  84. return false;
  85. }
  86. return true;
  87. }
  88. public static function InstallQuery($sql, $verbose = true)
  89. {
  90. $con = Propel::getConnection();
  91. try {
  92. $con->exec($sql);
  93. if ($verbose) {
  94. echo "done.\n";
  95. }
  96. } catch (Exception $e) {
  97. echo "Error!\n".$e->getMessage()."\n";
  98. echo " SQL statement was:\n";
  99. echo " ".$sql."\n\n";
  100. }
  101. }
  102. public static function DropSequence($p_sequenceName)
  103. {
  104. AirtimeInstall::InstallQuery("DROP SEQUENCE IF EXISTS $p_sequenceName", false);
  105. }
  106. /**
  107. * Try to connect to the database. Return true on success, false on failure.
  108. * @param boolean $p_exitOnError
  109. * Exit the program on failure.
  110. * @return boolean
  111. */
  112. public static function DbConnect($p_exitOnError = true)
  113. {
  114. $CC_CONFIG = Config::getConfig();
  115. try {
  116. $con = Propel::getConnection();
  117. } catch (Exception $e) {
  118. echo $e->getMessage().PHP_EOL;
  119. echo "Database connection problem.".PHP_EOL;
  120. echo "Check if database '{$CC_CONFIG['dsn']['database']}' exists".
  121. " with corresponding permissions.".PHP_EOL;
  122. if ($p_exitOnError) {
  123. exit(1);
  124. }
  125. return false;
  126. }
  127. return true;
  128. }
  129. /* TODO: This function should be moved to the media-monitor
  130. * install script. */
  131. public static function InstallStorageDirectory()
  132. {
  133. $CC_CONFIG = Config::getConfig();
  134. echo "* Storage directory setup".PHP_EOL;
  135. $ini = parse_ini_file(__DIR__."/airtime-install.ini");
  136. $stor_dir = $ini["storage_dir"];
  137. $dirs = array($stor_dir, $stor_dir."/organize");
  138. foreach ($dirs as $dir){
  139. if (!file_exists($dir)) {
  140. if (mkdir($dir, 02775, true)){
  141. $rp = realpath($dir);
  142. echo "* Directory $rp created".PHP_EOL;
  143. } else {
  144. echo "* Failed creating {$dir}".PHP_EOL;
  145. exit(1);
  146. }
  147. }
  148. else if (is_writable($dir)) {
  149. $rp = realpath($dir);
  150. echo "* Skipping directory already exists: $rp".PHP_EOL;
  151. }
  152. else {
  153. $rp = realpath($dir);
  154. echo "* Error: Directory already exists, but is not writable: $rp".PHP_EOL;
  155. exit(1);
  156. }
  157. echo "* Giving Apache permission to access $rp".PHP_EOL;
  158. $success = chown($rp, $CC_CONFIG["webServerUser"]);
  159. $success = chgrp($rp, $CC_CONFIG["webServerUser"]);
  160. $success = chmod($rp, 0775);
  161. }
  162. }
  163. public static function CreateDatabaseUser()
  164. {
  165. $CC_CONFIG = Config::getConfig();
  166. echo " * Creating Airtime database user".PHP_EOL;
  167. $username = $CC_CONFIG['dsn']['username'];
  168. $password = $CC_CONFIG['dsn']['password'];
  169. $command = "echo \"CREATE USER $username ENCRYPTED PASSWORD '$password' LOGIN CREATEDB NOCREATEUSER;\" | su postgres -c psql 2>/dev/null";
  170. @exec($command, $output, $results);
  171. if ($results == 0) {
  172. echo " * Database user '{$CC_CONFIG['dsn']['username']}' created.".PHP_EOL;
  173. } else {
  174. if (count($output) > 0) {
  175. echo " * Could not create user '{$CC_CONFIG['dsn']['username']}': ".PHP_EOL;
  176. echo implode(PHP_EOL, $output);
  177. }
  178. else {
  179. echo " * Database user '{$CC_CONFIG['dsn']['username']}' already exists.".PHP_EOL;
  180. }
  181. }
  182. }
  183. public static function CreateDatabase()
  184. {
  185. $CC_CONFIG = Config::getConfig();
  186. $database = $CC_CONFIG['dsn']['database'];
  187. $username = $CC_CONFIG['dsn']['username'];
  188. #$command = "echo \"CREATE DATABASE $database OWNER $username\" | su postgres -c psql 2>/dev/null";
  189. echo " * Creating Airtime database: " . $database . PHP_EOL;
  190. putenv("LC_ALL=en_CA.UTF-8"); //Squash warnings when running unit tests
  191. $command = "su postgres -c \"psql -l | cut -f2 -d' ' | grep -w '{$database}'\";";
  192. exec($command, $output, $rv);
  193. if ($rv == 0) {
  194. //database already exists
  195. echo "Database already exists." . PHP_EOL;
  196. return true;
  197. }
  198. $command = "sudo -i -u postgres psql postgres -c \"CREATE DATABASE ".$database." WITH ENCODING 'UTF8' TEMPLATE template0 OWNER ".$username."\"";
  199. @exec($command, $output, $results);
  200. if ($results == 0) {
  201. echo " * Database $database created.".PHP_EOL;
  202. } else {
  203. if (count($output) > 0) {
  204. echo " * Could not create database $database: ".PHP_EOL;
  205. echo implode(PHP_EOL, $output);
  206. }
  207. else {
  208. echo " * Database $database already exists.".PHP_EOL;
  209. }
  210. }
  211. $databaseExisted = ($results != 0);
  212. return $databaseExisted;
  213. }
  214. public static function InstallPostgresScriptingLanguage()
  215. {
  216. $con = Propel::getConnection();
  217. // Install postgres scripting language
  218. $sql = 'SELECT COUNT(*) FROM pg_language WHERE lanname = \'plpgsql\'';
  219. $langIsInstalled = $con->query($sql)->fetchColumn(0);
  220. if ($langIsInstalled == '0') {
  221. echo " * Installing Postgres scripting language".PHP_EOL;
  222. $sql = "CREATE LANGUAGE 'plpgsql'";
  223. AirtimeInstall::InstallQuery($sql, false);
  224. } else {
  225. echo " * Postgres scripting language already installed".PHP_EOL;
  226. }
  227. }
  228. public static function CreateDatabaseTables($p_dbuser, $p_dbpasswd, $p_dbname, $p_dbhost)
  229. {
  230. echo " * Creating database tables".PHP_EOL;
  231. // Put Propel sql files in Database
  232. //$command = AirtimeInstall::CONF_DIR_WWW."/library/propel/generator/bin/propel-gen ".AirtimeInstall::CONF_DIR_WWW."/build/ insert-sql 2>/dev/null";
  233. $dir = self::GetAirtimeSrcDir()."/build/sql/";
  234. $files = array("schema.sql", "sequences.sql", "views.sql", "triggers.sql", "defaultdata.sql");
  235. foreach ($files as $f){
  236. $command = "export PGPASSWORD=$p_dbpasswd && psql --username $p_dbuser --dbname $p_dbname --host $p_dbhost --file $dir$f 2>&1";
  237. @exec($command, $output, $results);
  238. }
  239. AirtimeInstall::$databaseTablesCreated = true;
  240. }
  241. public static function BypassMigrations($dir, $version)
  242. {
  243. $appDir = AirtimeInstall::GetAirtimeSrcDir();
  244. $command = "php $appDir/library/doctrine/migrations/doctrine-migrations.phar ".
  245. "--configuration=$dir/../../DoctrineMigrations/migrations.xml ".
  246. "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ".
  247. "--no-interaction --add migrations:version $version";
  248. system($command);
  249. }
  250. public static function MigrateTablesToVersion($dir, $version)
  251. {
  252. $appDir = AirtimeInstall::GetAirtimeSrcDir();
  253. $command = "php $appDir/library/doctrine/migrations/doctrine-migrations.phar ".
  254. "--configuration=$dir/../../DoctrineMigrations/migrations.xml ".
  255. "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ".
  256. "--no-interaction migrations:migrate $version";
  257. system($command);
  258. }
  259. public static function SetAirtimeVersion($p_version)
  260. {
  261. $con = Propel::getConnection();
  262. $sql = "DELETE FROM cc_pref WHERE keystr = 'system_version'";
  263. $con->exec($sql);
  264. Application_Model_Preference::SetAirtimeVersion($p_version);
  265. }
  266. public static function SetUniqueId()
  267. {
  268. $uniqueId = md5(uniqid("", true));
  269. Application_Model_Preference::SetUniqueId($uniqueId);
  270. }
  271. public static function GetAirtimeVersion()
  272. {
  273. $con = Propel::getConnection();
  274. $sql = "SELECT valstr FROM cc_pref WHERE keystr = 'system_version' LIMIT 1";
  275. $version = $con->query($sql)->fetchColumn(0);
  276. return $version;
  277. }
  278. public static function DeleteFilesRecursive($p_path)
  279. {
  280. $command = "rm -rf \"$p_path\"";
  281. exec($command);
  282. }
  283. public static function InstallPhpCode()
  284. {
  285. $CC_CONFIG = Config::getConfig();
  286. echo "* Installing PHP code to ".AirtimeInstall::CONF_DIR_WWW.PHP_EOL;
  287. exec("mkdir -p ".AirtimeInstall::CONF_DIR_WWW);
  288. exec("cp -R ".AirtimeInstall::GetAirtimeSrcDir()."/* ".AirtimeInstall::CONF_DIR_WWW);
  289. }
  290. public static function UninstallPhpCode()
  291. {
  292. echo "* Removing PHP code from ".AirtimeInstall::CONF_DIR_WWW.PHP_EOL;
  293. exec('rm -rf "'.AirtimeInstall::CONF_DIR_WWW.'"');
  294. }
  295. public static function DirCheck()
  296. {
  297. echo "Legend: \"+\" means the dir/file exists, \"-\" means that it does not.".PHP_EOL;
  298. $dirs = array(AirtimeInstall::CONF_DIR_BINARIES,
  299. AirtimeInstall::CONF_DIR_WWW,
  300. AirtimeIni::CONF_FILE_AIRTIME,
  301. AirtimeIni::CONF_FILE_LIQUIDSOAP,
  302. AirtimeIni::CONF_FILE_PYPO,
  303. AirtimeIni::CONF_FILE_RECORDER,
  304. "/usr/lib/airtime/pypo",
  305. "/var/log/airtime",
  306. "/var/log/airtime/pypo",
  307. "/var/tmp/airtime/pypo");
  308. foreach ($dirs as $f) {
  309. if (file_exists($f)) {
  310. echo "+ $f".PHP_EOL;
  311. } else {
  312. echo "- $f".PHP_EOL;
  313. }
  314. }
  315. }
  316. public static function CreateZendPhpLogFile(){
  317. $CC_CONFIG = Config::getConfig();
  318. $path = AirtimeInstall::CONF_DIR_LOG;
  319. $file = $path.'/zendphp.log';
  320. if (!file_exists($path)){
  321. mkdir($path, 0755, true);
  322. }
  323. touch($file);
  324. chmod($file, 0644);
  325. chown($file, $CC_CONFIG['webServerUser']);
  326. chgrp($file, $CC_CONFIG['webServerUser']);
  327. }
  328. public static function RemoveLogDirectories(){
  329. $path = AirtimeInstall::CONF_DIR_LOG;
  330. echo "* Removing logs directory ".$path.PHP_EOL;
  331. exec("rm -rf \"$path\"");
  332. }
  333. public static function CreateCronFile(){
  334. echo "* Creating Cron File".PHP_EOL;
  335. // Create CRON task to run every day. Time of day is initialized to a random time.
  336. $hour = rand(0,23);
  337. $minute = rand(0,59);
  338. $fp = fopen('/etc/cron.d/airtime-crons','w');
  339. fwrite($fp, "$minute $hour * * * root /usr/lib/airtime/utils/phone_home_stat\n");
  340. fclose($fp);
  341. }
  342. public static function removeVirtualEnvDistributeFile(){
  343. echo "* Removing distribute-0.6.10.tar.gz".PHP_EOL;
  344. if(file_exists('/usr/share/python-virtualenv/distribute-0.6.10.tar.gz')){
  345. exec("rm -f /usr/share/python-virtualenv/distribute-0.6.10.tar.gz");
  346. }
  347. }
  348. public static function printUsage($opts)
  349. {
  350. $msg = $opts->getUsageMessage();
  351. echo PHP_EOL."Usage: airtime-install [options]";
  352. echo substr($msg, strpos($msg, "\n")).PHP_EOL;
  353. }
  354. public static function getOpts()
  355. {
  356. try {
  357. $autoloader = Zend_Loader_Autoloader::getInstance();
  358. $opts = new Zend_Console_Getopt(
  359. array(
  360. 'help|h' => 'Displays usage information.',
  361. 'overwrite|o' => 'Overwrite any existing config files.',
  362. 'preserve|p' => 'Keep any existing config files.',
  363. 'no-db|n' => 'Turn off database install.',
  364. 'reinstall|r' => 'Force a fresh install of this Airtime Version',
  365. 'webonly|w' => 'Install only web files'
  366. )
  367. );
  368. $opts->parse();
  369. } catch (Zend_Console_Getopt_Exception $e) {
  370. print $e->getMessage() .PHP_EOL;
  371. AirtimeInstall::printUsage($opts);
  372. return NULL;
  373. }
  374. return $opts;
  375. }
  376. public static function checkPHPVersion()
  377. {
  378. if (PHP_VERSION_ID < 50300)
  379. {
  380. echo "Error: Airtime requires PHP 5.3 or greater.";
  381. return false;
  382. }
  383. return true;
  384. }
  385. }