Add database creation page

refs #7163
This commit is contained in:
Johannes Meyer 2014-10-01 09:16:53 +02:00
parent c78b016d74
commit 08d259eccf
3 changed files with 295 additions and 5 deletions

View File

@ -0,0 +1,144 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Setup;
use PDOException;
use Icinga\Web\Form;
use Icinga\Web\Form\Element\Note;
use Icinga\Web\Setup\DbTool;
/**
* Wizard page to define a database user that is able to create databases and tables
*/
class DatabaseCreationPage extends Form
{
/**
* The resource configuration to use
*
* @var array
*/
protected $config;
/**
* The required database privileges
*
* @var array
*/
protected $databasePrivileges;
/**
* Initialize this page
*/
public function init()
{
$this->setName('setup_database_creation');
}
/**
* Set the resource configuration to use
*
* @param array $config
*
* @return self
*/
public function setResourceConfig(array $config)
{
$this->config = $config;
return $this;
}
/**
* Set the required database privileges
*
* @param array $privileges The required privileges
*
* @return self
*/
public function setDatabasePrivileges(array $privileges)
{
$this->databasePrivileges = $privileges;
return $this;
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
$this->addElement(
new Note(
'description',
array(
'value' => t(
'It seems that either the database you defined earlier does not yet exist and cannot be created'
. ' using the provided access credentials or the database does not have the required schema to '
. 'be operated by Icinga Web 2. Please provide appropriate access credentials to solve this.'
)
)
)
);
$this->addElement(
'text',
'username',
array(
'required' => true,
'label' => t('Username'),
'description' => t('A user which is able to create databases and/or touch the database schema')
)
);
$this->addElement(
'password',
'password',
array(
'required' => true,
'label' => t('Password'),
'description' => t('The password for the database user defined above')
)
);
}
/**
* Validate the given form data and check whether the defined user has sufficient access rights
*
* @param array $data The data to validate
*
* @return bool
*/
public function isValid($data)
{
if (false === parent::isValid($data)) {
return false;
}
$this->config['username'] = $this->getValue('username');
$this->config['password'] = $this->getValue('password');
$db = new DbTool($this->config);
try {
$db->connectToDb();
if (false === $db->checkPrivileges($this->databasePrivileges)) {
$this->addError(
t('The provided credentials do not have the required access rights to create the database schema.')
);
return false;
}
} catch (PDOException $e) {
try {
$db->connectToHost();
if (false === $db->checkPrivileges($this->databasePrivileges)) {
$this->addError(
t('The provided credentials cannot be used to create the database and/or the user.')
);
return false;
}
} catch (PDOException $e) {
$this->addError($e->getMessage());
return false;
}
}
return true;
}
}

View File

@ -4,6 +4,7 @@
namespace Icinga\Application;
use PDOException;
use Icinga\Form\Setup\WelcomePage;
use Icinga\Form\Setup\DbResourcePage;
use Icinga\Form\Setup\PreferencesPage;
@ -13,9 +14,11 @@ use Icinga\Form\Setup\LdapResourcePage;
use Icinga\Form\Setup\RequirementsPage;
use Icinga\Form\Setup\GeneralConfigPage;
use Icinga\Form\Setup\AuthenticationPage;
use Icinga\Form\Setup\DatabaseCreationPage;
use Icinga\Web\Form;
use Icinga\Web\Wizard;
use Icinga\Web\Request;
use Icinga\Web\Setup\DbTool;
use Icinga\Web\Setup\SetupWizard;
use Icinga\Web\Setup\Requirements;
use Icinga\Application\Platform;
@ -25,6 +28,31 @@ use Icinga\Application\Platform;
*/
class WebSetup extends Wizard implements SetupWizard
{
/**
* The database tables required by Icinga Web 2
*
* @var array
*/
protected $databaseTables = array('account', 'preference');
/**
* The privileges required by Icinga Web 2 to setup the database
*
* @var array
*/
protected $databaseSetupPrivileges = array(
'USAGE',
'CREATE',
'ALTER',
'INSERT',
'UPDATE',
'DELETE',
'TRUNCATE',
'REFERENCES',
'CREATE USER',
'GRANT OPTION'
);
/**
* @see Wizard::init()
*/
@ -37,8 +65,9 @@ class WebSetup extends Wizard implements SetupWizard
$this->addPage(new DbResourcePage());
$this->addPage(new LdapResourcePage());
$this->addPage(new AuthBackendPage());
$this->addPage(new GeneralConfigPage());
$this->addPage(new AdminAccountPage());
$this->addPage(new GeneralConfigPage());
$this->addPage(new DatabaseCreationPage());
}
/**
@ -68,6 +97,9 @@ class WebSetup extends Wizard implements SetupWizard
} elseif ($authData['type'] === 'ldap') {
$page->setResourceConfig($this->getPageData('setup_ldap_resource'));
}
} elseif ($page->getName() === 'setup_database_creation') {
$page->setDatabasePrivileges($this->databaseSetupPrivileges);
$page->setResourceConfig($this->getPageData('setup_db_resource'));
}
}
@ -85,6 +117,25 @@ class WebSetup extends Wizard implements SetupWizard
} elseif ($newPage->getName() === 'setup_ldap_resource') {
$authData = $this->getPageData('setup_authentication_type');
$skip = $authData['type'] !== 'ldap';
} elseif ($newPage->getName() === 'setup_database_creation') {
if ($this->hasPageData('setup_db_resource')) {
$db = new DbTool($this->getPageData('setup_db_resource'));
try {
$db->connectToDb();
$diff = array_diff($this->databaseTables, $db->listTables());
if (false === empty($diff)) {
$skip = $db->checkPrivileges($this->databaseSetupPrivileges);
} else {
$skip = true;
}
} catch (PDOException $e) {
$db->connectToHost();
$skip = $db->checkPrivileges($this->databaseSetupPrivileges);
}
} else {
$skip = true;
}
}
if ($skip) {

View File

@ -6,6 +6,9 @@ namespace Icinga\Web\Setup;
use PDO;
use PDOException;
use LogicException;
use Zend_Db_Adapter_Pdo_Mysql;
use Zend_Db_Adapter_Pdo_Pgsql;
use Icinga\Exception\ConfigurationError;
/**
@ -14,11 +17,18 @@ use Icinga\Exception\ConfigurationError;
class DbTool
{
/**
* The database connection
* The PDO database connection
*
* @var PDO
*/
protected $conn;
protected $pdoConn;
/**
* The Zend database adapter
*
* @var Zend_Db_Adapter_Pdo_Abstract
*/
protected $zendConn;
/**
* The resource configuration
@ -39,21 +49,27 @@ class DbTool
/**
* Connect to the server
*
* @return self
*/
public function connectToHost()
{
$this->assertHostAccess();
$this->connect();
return $this;
}
/**
* Connect to the database
*
* @return self
*/
public function connectToDb()
{
$this->assertHostAccess();
$this->assertDatabaseAccess();
$this->connect($this->config['dbname']);
return $this;
}
/**
@ -88,6 +104,18 @@ class DbTool
}
}
/**
* Assert that a connection with a database has been established
*
* @throws LogicException
*/
protected function assertConnectedToDb()
{
if ($this->zendConn === null) {
throw new LogicException('Not connected to database');
}
}
/**
* Establish a connection with the database or just the server by omitting the database name
*
@ -95,11 +123,55 @@ class DbTool
*/
public function connect($dbname = null)
{
if ($this->conn !== null) {
$this->_pdoConnect($dbname);
if ($dbname !== null) {
$this->_zendConnect($dbname);
}
}
/**
* Initialize Zend database adapter
*
* @param string $dbname The name of the database to connect with
*
* @throws ConfigurationError In case the resource type is not a supported PDO driver name
*/
protected function _zendConnect($dbname)
{
if ($this->zendConn !== null) {
return;
}
$this->conn = new PDO(
$config = array(
'dbname' => $dbname,
'username' => $this->config['username'],
'password' => $this->config['password']
);
if ($this->config['db'] === 'mysql') {
$this->zendConn = new Zend_Db_Adapter_Pdo_Mysql($config);
} elseif ($this->config['db'] === 'pgsql') {
$this->zendConn = new Zend_Db_Adapter_Pdo_Pgsql($config);
} else {
throw new ConfigurationError(
'Failed to connect to database. Unsupported PDO driver "%s"',
$this->config['db']
);
}
}
/**
* Initialize PDO connection
*
* @param string $dbname The name of the database to connect with
*/
protected function _pdoConnect($dbname)
{
if ($this->pdoConn !== null) {
return;
}
$this->pdoConn = new PDO(
$this->buildDsn($this->config['db'], $dbname),
$this->config['username'],
$this->config['password'],
@ -155,4 +227,27 @@ class DbTool
}
}
}
/**
* Return whether the given privileges were granted
*
* @param array $privileges An array of strings with the required privilege names
*
* @return bool
*/
public function checkPrivileges(array $privileges)
{
return true; // TODO(7163): Implement privilege checks
}
/**
* Return a list of all existing database tables
*
* @return array
*/
public function listTables()
{
$this->assertConnectedToDb();
return $this->zendConn->listTables();
}
}