From ad5536dedd762bf3078a7c802333d6e01d3dc1e1 Mon Sep 17 00:00:00 2001 From: Duncan Sommerville Date: Thu, 12 Feb 2015 15:39:22 -0500 Subject: [PATCH] SAAS-582 - Added provisioning class to create database from within Airtime --- airtime_mvc/application/Bootstrap.php | 6 + .../application/common/ProvisioningHelper.php | 132 ++++++++++++++++++ .../controllers/ProvisioningController.php | 76 ---------- 3 files changed, 138 insertions(+), 76 deletions(-) create mode 100644 airtime_mvc/application/common/ProvisioningHelper.php diff --git a/airtime_mvc/application/Bootstrap.php b/airtime_mvc/application/Bootstrap.php index 988e5ee4a..fb6ec0ddc 100644 --- a/airtime_mvc/application/Bootstrap.php +++ b/airtime_mvc/application/Bootstrap.php @@ -21,6 +21,7 @@ require_once "LocaleHelper.php"; require_once "HTTPHelper.php"; require_once "OsPath.php"; require_once "Database.php"; +require_once "ProvisioningHelper.php"; require_once "Timezone.php"; require_once "Auth.php"; require_once __DIR__.'/forms/helpers/ValidationTypes.php'; @@ -33,6 +34,11 @@ require_once __DIR__.'/modules/rest/controllers/MediaController.php'; require_once (APPLICATION_PATH."/logging/Logging.php"); Logging::setLogPath('/var/log/airtime/zendphp.log'); +if (strpos("/provisioning/create-database", $_SERVER["REDIRECT_URL"]) !== false) { + (new ProvisioningHelper($CC_CONFIG["apiKey"][0]))->createDatabaseAction(); + die; +} + Config::setAirtimeVersion(); require_once __DIR__."/configs/navigation.php"; diff --git a/airtime_mvc/application/common/ProvisioningHelper.php b/airtime_mvc/application/common/ProvisioningHelper.php new file mode 100644 index 000000000..0537f5f60 --- /dev/null +++ b/airtime_mvc/application/common/ProvisioningHelper.php @@ -0,0 +1,132 @@ +apikey = $apikey; + } + + /** + * Endpoint for setting up and installing the Airtime database + */ + public function createDatabaseAction() { + Logging::info("Create Database action received"); + + $this->getParams(); + Logging::info("Parameters: " + . "\nUser: " . $this->dbuser + . "\nPass: " . $this->dbpass + . "\nName: " . $this->dbname + . "\nHost: " . $this->dbhost + . "\nOwner: " . $this->dbowner); + + $apikey = $_SERVER['PHP_AUTH_USER']; + if (!isset($apikey) || $apikey != $this->apikey) { + Logging::info("Invalid API Key: $apikey"); + http_response_code(403); + echo "ERROR: Incorrect API key"; + return; + } + + try { + $this->setNewDatabaseConnection(); + if ($this->checkDatabaseExists()) { + throw new Exception("ERROR: Airtime database already exists"); + } + $this->createDatabase(); + $this->createDatabaseTables(); + } catch(Exception $e) { + http_response_code(400); + Logging::info($e->getMessage()); + echo $e->getMessage(); + return; + } + + http_response_code(201); + } + + /** + * Check if the database settings and credentials given are valid + * @return boolean true if the database given exists and the user is valid and can access it + */ + private function checkDatabaseExists() { + $statement = self::$dbh->prepare("SELECT datname FROM pg_database WHERE datname = :dbname"); + $statement->execute(array(":dbname" => $this->dbname)); + $result = $statement->fetch(); + return isset($result[0]); + } + + private function getParams() { + $params = []; + parse_str($_SERVER["QUERY_STRING"], $params); + foreach ($params as $k => $v) { + $this->$k = $v; + } + } + + /** + * Set up a new database connection based on the parameters in the request + * @throws PDOException upon failure to connect + */ + private function setNewDatabaseConnection() { + self::$dbh = new PDO("pgsql:host=" . $this->dbhost + . ";dbname=postgres" + . ";port=5432" . ";user=" . $this->dbuser + . ";password=" . $this->dbpass); + $err = self::$dbh->errorInfo(); + if ($err[1] != null) { + throw new PDOException("ERROR: Could not connect to database"); + } + } + + /** + * Creates the Airtime database using the given credentials + * @throws Exception + */ + private function createDatabase() { + Logging::info("Creating database..."); + $statement = self::$dbh->prepare("CREATE DATABASE " . pg_escape_string($this->dbname) + . " WITH ENCODING 'UTF8' TEMPLATE template0" + . " OWNER " . pg_escape_string($this->dbowner)); + if (!$statement->execute()) { + throw new Exception("ERROR: Failed to create Airtime database"); + } + } + + /** + * Install the Airtime database + * @throws Exception + */ + private function createDatabaseTables() { + $sqlDir = dirname(APPLICATION_PATH) . "/build/sql/"; + $files = array("schema.sql", "sequences.sql", "views.sql", "triggers.sql", "defaultdata.sql"); + foreach ($files as $f) { + try { + /* + * Unfortunately, we need to use exec here due to PDO's lack of support for importing + * multi-line .sql files. PDO->exec() almost works, but any SQL errors stop the import, + * so the necessary DROPs on non-existent tables make it unusable. Prepared statements + * have multiple issues; they similarly die on any SQL errors, fail to read in multi-line + * commands, and fail on any unescaped ? or $ characters. + */ + exec("export PGPASSWORD=" . $this->dbpass . " && psql -U " . $this->dbuser . " --dbname " + . $this->dbname . " -h " . $this->dbhost . " -f $sqlDir$f 2>/dev/null", $out, $status); + } catch (Exception $e) { + throw new Exception("ERROR: Failed to create database tables"); + } + } + } + +} \ No newline at end of file diff --git a/airtime_mvc/application/controllers/ProvisioningController.php b/airtime_mvc/application/controllers/ProvisioningController.php index 4186fd05b..6c2ea2a5d 100644 --- a/airtime_mvc/application/controllers/ProvisioningController.php +++ b/airtime_mvc/application/controllers/ProvisioningController.php @@ -7,11 +7,6 @@ use Aws\S3\S3Client; class ProvisioningController extends Zend_Controller_Action { - static $dbh; - - // Parameter values - private $dbuser, $dbpass, $dbname, $dbhost; - public function init() { } @@ -39,76 +34,5 @@ class ProvisioningController extends Zend_Controller_Action ->setHttpResponseCode(200) ->appendBody("OK"); } - - /** - * RESTful endpoint for setting up and installing the Airtime database - */ - public function createDatabaseAction() { - Logging::info("Create Database action received"); - - if (!RestAuth::verifyAuth(true, true, $this)) { - return; - } - - try { - $this->getParams(); - $this->setNewDatabaseConnection(); - $this->createDatabaseTables(); - } catch(Exception $e) { - $this->getResponse() - ->setHttpResponseCode(400) - ->appendBody($e->getMessage()); - return; - } - - $this->getResponse() - ->setHttpResponseCode(201); - } - - private function getParams() { - $this->dbuser = $this->_getParam('dbuser', ''); - $this->dbpass = $this->_getParam('dbpass', ''); - $this->dbname = $this->_getParam('dbname', ''); - $this->dbhost = $this->_getParam('dbhost', ''); - } - - /** - * Set up a new database connection based on the parameters in the request - * @throws PDOException upon failure to connect - */ - private function setNewDatabaseConnection() { - self::$dbh = new PDO("pgsql:host=" . $this->dbhost - . ";dbname=" . $this->dbname - . ";port=5432" . ";user=" . $this->dbuser - . ";password=" . $this->dbpass); - $err = self::$dbh->errorInfo(); - if ($err[1] != null) { - throw new PDOException("ERROR: Could not connect to database"); - } - } - - /** - * Install the Airtime database - * @throws Exception - */ - private function createDatabaseTables() { - $sqlDir = dirname(APPLICATION_PATH) . "/build/sql/"; - $files = array("schema.sql", "sequences.sql", "views.sql", "triggers.sql", "defaultdata.sql"); - foreach ($files as $f) { - try { - /* - * Unfortunately, we need to use exec here due to PDO's lack of support for importing - * multi-line .sql files. PDO->exec() almost works, but any SQL errors stop the import, - * so the necessary DROPs on non-existent tables make it unusable. Prepared statements - * have multiple issues; they similarly die on any SQL errors, fail to read in multi-line - * commands, and fail on any unescaped ? or $ characters. - */ - exec("export PGPASSWORD=" . $this->dbpass . " && psql -U " . $this->dbuser . " --dbname " - . $this->dbname . " -h " . $this->dbhost . " -f $sqlDir$f 2>/dev/null", $out, $status); - } catch (Exception $e) { - throw new Exception("ERROR: Failed to create database tables"); - } - } - } }