Alon Bar-Lev has uploaded a new change for review.

Change subject: packaging: setup: reusable postresql provisioning
......................................................................

packaging: setup: reusable postresql provisioning

took the simple approach... each installer will use provisioning as-is,
it may cause postgres multiple restarts and such, but it keeps loosely
coupled components.

Change-Id: Ieff824fa5115954925f8fd7cabf59d535f39e96c
Signed-off-by: Alon Bar-Lev <[email protected]>
---
M packaging/setup/ovirt_engine_setup/constants.py
A packaging/setup/ovirt_engine_setup/postgres.py
A 
packaging/setup/plugins/ovirt-engine-setup/ovirt-engine-common/provisioning/__init__.py
A 
packaging/setup/plugins/ovirt-engine-setup/ovirt-engine-common/provisioning/postgres.py
M 
packaging/setup/plugins/ovirt-engine-setup/ovirt-engine/provisioning/postgres.py
5 files changed, 688 insertions(+), 507 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/21/23121/1

diff --git a/packaging/setup/ovirt_engine_setup/constants.py 
b/packaging/setup/ovirt_engine_setup/constants.py
index f3f4914..f39ed5a 100644
--- a/packaging/setup/ovirt_engine_setup/constants.py
+++ b/packaging/setup/ovirt_engine_setup/constants.py
@@ -496,7 +496,6 @@
     DB_CONNECTION_SETUP = 'osetup.db.connection.setup'
     DB_CONNECTION_CUSTOMIZATION = 'osetup.db.connection.customization'
     DB_CONNECTION_STATUS = 'osetup.db.connection.status'
-    DB_HOST_LOCATION_CUSTOMIZATION = 'osetup.db.hostlocation.customization'
     DB_CREDENTIALS_AVAILABLE_EARLY = 'osetup.db.connection.credentials.early'
     DB_CREDENTIALS_AVAILABLE_LATE = 'osetup.db.connection.credentials.late'
     DB_CONNECTION_AVAILABLE = 'osetup.db.connection.available'
diff --git a/packaging/setup/ovirt_engine_setup/postgres.py 
b/packaging/setup/ovirt_engine_setup/postgres.py
new file mode 100644
index 0000000..7add279
--- /dev/null
+++ b/packaging/setup/ovirt_engine_setup/postgres.py
@@ -0,0 +1,556 @@
+#
+# ovirt-engine-setup -- ovirt engine setup
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+import datetime
+import os
+import platform
+import random
+import re
+import time
+import gettext
+_ = lambda m: gettext.dgettext(message=m, domain='ovirt-engine-setup')
+
+
+from otopi import base
+from otopi import util
+from otopi import transaction
+from otopi import filetransaction
+from otopi import constants as otopicons
+
+
+from ovirt_engine_setup import constants as osetupcons
+from ovirt_engine_setup import database
+from ovirt_engine_setup import util as osetuputil
+
+
[email protected]
+class AlternateUser(object):
+    def __init__(self, user):
+        self._user = osetuputil.getUid(user)
+
+    def __enter__(self):
+        os.seteuid(self._user)
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        os.seteuid(os.getuid())
+
+
[email protected]
+class Provisioning(base.Base):
+
+    _PASSWORD_CHARS = (
+        '0123456789' +
+        'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
+        'abcdefghijklmnopqrstuvwxyz'
+    )
+
+    _RE_POSTGRES_PGHBA_LOCAL = re.compile(
+        flags=re.VERBOSE,
+        pattern=r"""
+            ^
+            (?P<host>local)
+            \s+
+            .*
+            \s+
+            (?P<param>\w+)
+            $
+        """,
+    )
+
+    _RE_KEY_VALUE = re.compile(
+        flags=re.VERBOSE,
+        pattern=r"""
+            ^
+            \s*
+            (?P<key>\w+)
+            \s*
+            =
+            \s*
+            (?P<value>\w+)
+        """,
+    )
+
+    @property
+    def environment(self):
+        return self._plugin.environment
+
+    @property
+    def command(self):
+        return self._plugin.command
+
+    @property
+    def services(self):
+        return self._plugin.services
+
+    @property
+    def databaseRenamed(self):
+        return self._renamedDBResources
+
+    def _setDatabaseResources(self, environment):
+        dbstatement = database.Statement(
+            dbenvkeys=self._dbenvkeys,
+            environment=environment,
+        )
+        hasDatabase = dbstatement.execute(
+            statement="""
+                select count(*) as count
+                from pg_database
+                where datname = %(database)s
+            """,
+            args=dict(
+                database=self.environment[
+                    self._dbenvkeys['database']
+                ],
+            ),
+            ownConnection=True,
+            transaction=False,
+        )[0]['count'] != 0
+        hasUser = dbstatement.execute(
+            statement="""
+                select count(*) as count
+                from pg_user
+                where usename = %(user)s
+            """,
+            args=dict(
+                user=self.environment[
+                    self._dbenvkeys['user']
+                ],
+            ),
+            ownConnection=True,
+            transaction=False,
+        )[0]['count'] != 0
+
+        generate = hasDatabase or hasUser
+        existing = False
+
+        if hasDatabase and hasUser:
+            dbovirtutils = database.OvirtUtils(
+                plugin=self,
+                dbenvkeys=self._dbenvkeys,
+                environment=environment,
+            )
+            if dbovirtutils.isNewDatabase(
+                database=self.environment[
+                    self._dbenvkeys['database']
+                ],
+            ):
+                self.logger.debug('Found empty database')
+                generate = False
+                existing = True
+            else:
+                generate = True
+
+        if generate:
+            self.logger.debug('Existing resources found, generating names')
+            suffix = '_%s' % datetime.datetime.now().strftime('%Y%m%d%H%M%S')
+            self.environment[self._dbenvkeys['database']] += suffix
+            self.environment[self._dbenvkeys['user']] += suffix
+            self._renamedDBResources = True
+
+        return existing
+
+    def _performDatabase(
+        self,
+        environment,
+        op,
+    ):
+        statements = [
+            (
+                """
+                    {op} role {user}
+                    with
+                        login
+                        encrypted password %(password)s
+                """
+            ).format(
+                op=op,
+                user=self.environment[
+                    self._dbenvkeys['user']
+                ],
+            ),
+
+            (
+                """
+                    {op} database {database}
+                    owner {to} {user}
+                    {encoding}
+                """
+            ).format(
+                op=op,
+                to='to' if op == 'alter' else '',
+                database=self.environment[
+                    self._dbenvkeys['database']
+                ],
+                user=self.environment[
+                    self._dbenvkeys['user']
+                ],
+                encoding="""
+                    template template0
+                    encoding 'UTF8'
+                    lc_collate 'en_US.UTF-8'
+                    lc_ctype 'en_US.UTF-8'
+                """ if op != 'alter' else '',
+            ),
+        ]
+
+        dbstatement = database.Statement(
+            dbenvkeys=self._dbenvkeys,
+            environment=environment,
+        )
+        for statement in statements:
+            dbstatement.execute(
+                statement=statement,
+                args=dict(
+                    password=self.environment[
+                        self._dbenvkeys['password']
+                    ],
+                ),
+                ownConnection=True,
+                transaction=False,
+            )
+
+    def _initDbIfRequired(self):
+        if not os.path.exists(
+            self.environment[
+                osetupcons.ProvisioningEnv.POSTGRES_PG_VERSION
+            ]
+        ):
+            self.logger.info(_('Initializing PostgreSQL'))
+
+            setup = self.command.get(
+                command='postgresql-setup',
+                optional=True
+            )
+            if setup is not None:
+                # new method (post-systemd)
+                self._plugin.execute(
+                    (
+                        setup,
+                        'initdb',
+                    ),
+                )
+            else:
+                # old method (pre-systemd)
+                self._plugin.execute(
+                    (
+                        os.path.join(
+                            osetupcons.FileLocations.SYSCONFDIR,
+                            'init.d',
+                            self.environment[
+                                osetupcons.ProvisioningEnv.POSTGRES_SERVICE
+                            ],
+                        ),
+                        'initdb',
+                    ),
+                )
+
+    def _updateMaxConnections(
+        self,
+        transaction,
+        maxconn,
+    ):
+        with open(
+            self.environment[
+                osetupcons.ProvisioningEnv.POSTGRES_CONF
+            ]
+        ) as f:
+            content = f.read().splitlines()
+
+        needUpdate = True
+        for l in content:
+            m = self._RE_KEY_VALUE.match(l)
+            if (
+                m is not None and
+                m.group('key') == 'max_connections' and
+                int(m.group('value')) >= int(maxconn)
+            ):
+                needUpdate = False
+                break
+
+        if needUpdate:
+            content = osetuputil.editConfigContent(
+                content=content,
+                params={
+                    'max_connections': maxconn,
+                },
+            )
+
+            transaction.append(
+                filetransaction.FileTransaction(
+                    name=self.environment[
+                        osetupcons.ProvisioningEnv.POSTGRES_CONF
+                    ],
+                    content=content,
+                    modifiedList=self.environment[
+                        otopicons.CoreEnv.MODIFIED_FILES
+                    ],
+                ),
+            )
+            self.environment[
+                osetupcons.CoreEnv.UNINSTALL_UNREMOVABLE_FILES
+            ].append(
+                self.environment[
+                    osetupcons.ProvisioningEnv.POSTGRES_CONF
+                ]
+            )
+
+    def _setPgHbaLocalPeer(
+        self,
+        transaction,
+    ):
+        content = []
+        with open(
+            self.environment[
+                osetupcons.ProvisioningEnv.POSTGRES_PG_HBA
+            ]
+        ) as f:
+            for line in f.read().splitlines():
+                matcher = self._RE_POSTGRES_PGHBA_LOCAL.match(line)
+                if matcher is not None:
+                    line = line.replace(
+                        matcher.group('param'),
+                        'ident',  # we cannot use peer <psql-9
+                    )
+                content.append(line)
+
+        transaction.append(
+            filetransaction.FileTransaction(
+                name=self.environment[
+                    osetupcons.ProvisioningEnv.POSTGRES_PG_HBA
+                ],
+                content=content,
+                visibleButUnsafe=True,
+            )
+        )
+
+    def _addPgHbaDatabaseAccess(
+        self,
+        transaction,
+    ):
+        lines = [
+            # we cannot use all for address <psql-9
+            (
+                '{host:7} '
+                '{user:15} '
+                '{database:15} '
+                '{address:23} '
+                '{auth}'
+            ).format(
+                host='host',
+                user=self.environment[
+                    self._dbenvkeys['user']
+                ],
+                database=self.environment[
+                    self._dbenvkeys['database']
+                ],
+                address=address,
+                auth='md5',
+            )
+            for address in ('0.0.0.0/0', '::0/0')
+        ]
+
+        content = []
+        with open(
+            self.environment[
+                osetupcons.ProvisioningEnv.POSTGRES_PG_HBA
+            ]
+        ) as f:
+            for line in f.read().splitlines():
+                if line not in lines:
+                    content.append(line)
+
+                # order is important, add after local
+                # so we be first
+                if line.lstrip().startswith('local'):
+                    content.extend(lines)
+
+        transaction.append(
+            filetransaction.FileTransaction(
+                name=self.environment[
+                    osetupcons.ProvisioningEnv.POSTGRES_PG_HBA
+                ],
+                content=content,
+                modifiedList=self.environment[
+                    otopicons.CoreEnv.MODIFIED_FILES
+                ],
+            )
+        )
+        self.environment[
+            osetupcons.CoreEnv.UNINSTALL_UNREMOVABLE_FILES
+        ].append(
+            self.environment[
+                osetupcons.ProvisioningEnv.POSTGRES_PG_HBA
+            ]
+        )
+
+    def _restart(self):
+            for state in (False, True):
+                self.services.state(
+                    name=self.environment[
+                        osetupcons.ProvisioningEnv.POSTGRES_SERVICE
+                    ],
+                    state=state,
+                )
+
+    def _waitForDatabase(self, environment=None):
+        dbovirtutils = database.OvirtUtils(
+            plugin=self,
+            dbenvkeys=self._dbenvkeys,
+        )
+        for i in range(60):
+            try:
+                self.logger.debug('Attempting to connect database')
+                dbovirtutils.tryDatabaseConnect(environment=environment)
+                break
+            except RuntimeError:
+                self.logger.debug(
+                    'Database connection failed',
+                    exc_info=True,
+                )
+                time.sleep(1)
+            except Exception:
+                self.logger.debug(
+                    'Database connection failed, unknown exception',
+                    exc_info=True,
+                )
+                raise
+
+    def __init__(
+        self,
+        plugin,
+        dbenvkeys,
+        defaults,
+    ):
+        super(Provisioning, self).__init__()
+        self._plugin = plugin
+        self._dbenvkeys = dbenvkeys
+        self._defaults = defaults
+        self._renamedDBResources = False
+
+    def detectCommands(self):
+        self.command.detect('postgresql-setup')
+
+    def supported(self):
+        return platform.linux_distribution(
+            full_distribution_name=0
+        )[0] in ('redhat', 'fedora', 'centos')
+
+    def validate(self):
+        if not self.services.exists(
+            name=self.environment[
+                osetupcons.ProvisioningEnv.POSTGRES_SERVICE
+            ]
+        ):
+            raise RuntimeError(
+                _(
+                    'Database configuration was requested, '
+                    'however, postgresql service was not found. '
+                    'This may happen because postgresql database '
+                    'is not installed on system.'
+                )
+            )
+
+    def generatePassword(self):
+        return ''.join([random.choice(self._PASSWORD_CHARS) for i in range(8)])
+
+    def applyEnvironment(self):
+        for k in ('user', 'database', 'port', 'secured', 'hostValidation'):
+            self.environment[self._dbenvkeys[k]] = self._defaults[k]
+        self.environment[self._dbenvkeys['password']] = self.generatePassword()
+
+    def provision(self):
+        if not self.supported():
+            raise RuntimeError(
+                _(
+                    'Unsupported distribution for '
+                    'postgresql proisioning'
+                )
+            )
+
+        self._initDbIfRequired()
+
+        self.logger.info(
+            _("Creating PostgreSQL '{database}' database").format(
+                database=self.environment[self._dbenvkeys['database']],
+            )
+        )
+        localtransaction = transaction.Transaction()
+        try:
+            localtransaction.prepare()
+
+            self._setPgHbaLocalPeer(
+                transaction=localtransaction,
+            )
+
+            self._restart()
+
+            with AlternateUser(
+                user=self.environment[
+                    osetupcons.SystemEnv.USER_POSTGRES
+                ],
+            ):
+                usockenv = {
+                    self._dbenvkeys['host']: '',  # usock
+                    self._dbenvkeys['port']: '',
+                    self._dbenvkeys['secured']: False,
+                    self._dbenvkeys['hostValidation']: False,
+                    self._dbenvkeys['user']: 'postgres',
+                    self._dbenvkeys['password']: '',
+                    self._dbenvkeys['database']: 'template1',
+                }
+                self._waitForDatabase(
+                    environment=usockenv,
+                )
+                existing = self._setDatabaseResources(
+                    environment=usockenv,
+                )
+                self._performDatabase(
+                    environment=usockenv,
+                    op=(
+                        'alter' if existing
+                        else 'create'
+                    ),
+                )
+        finally:
+            # restore everything
+            localtransaction.abort()
+
+        self.logger.info(_('Configuring PostgreSQL'))
+        with transaction.Transaction() as localtransaction:
+            self._updateMaxConnections(
+                transaction=localtransaction,
+                maxconn=self.environment[
+                    osetupcons.ProvisioningEnv.POSTGRES_MAX_CONN
+                ],
+            )
+            self._addPgHbaDatabaseAccess(
+                transaction=localtransaction,
+            )
+
+        self.services.startup(
+            name=self.environment[
+                osetupcons.ProvisioningEnv.POSTGRES_SERVICE
+            ],
+            state=True,
+        )
+
+        self._restart()
+        self._waitForDatabase()
+
+
+# vim: expandtab tabstop=4 shiftwidth=4
diff --git 
a/packaging/setup/plugins/ovirt-engine-setup/ovirt-engine-common/provisioning/__init__.py
 
b/packaging/setup/plugins/ovirt-engine-setup/ovirt-engine-common/provisioning/__init__.py
new file mode 100644
index 0000000..42fd126
--- /dev/null
+++ 
b/packaging/setup/plugins/ovirt-engine-setup/ovirt-engine-common/provisioning/__init__.py
@@ -0,0 +1,33 @@
+#
+# ovirt-engine-setup -- ovirt engine setup
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+"""Provisioning plugin."""
+
+
+from otopi import util
+
+
+from . import postgres
+
+
[email protected]
+def createPlugins(context):
+    postgres.Plugin(context=context)
+
+
+# vim: expandtab tabstop=4 shiftwidth=4
diff --git 
a/packaging/setup/plugins/ovirt-engine-setup/ovirt-engine-common/provisioning/postgres.py
 
b/packaging/setup/plugins/ovirt-engine-setup/ovirt-engine-common/provisioning/postgres.py
new file mode 100644
index 0000000..8804c1a
--- /dev/null
+++ 
b/packaging/setup/plugins/ovirt-engine-setup/ovirt-engine-common/provisioning/postgres.py
@@ -0,0 +1,66 @@
+#
+# ovirt-engine-setup -- ovirt engine setup
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+"""Local Postgres plugin."""
+
+
+import gettext
+_ = lambda m: gettext.dgettext(message=m, domain='ovirt-engine-setup')
+
+
+from otopi import util
+from otopi import plugin
+
+
+from ovirt_engine_setup import constants as osetupcons
+
+
[email protected]
+class Plugin(plugin.PluginBase):
+    """Local Postgres plugin."""
+
+    def __init__(self, context):
+        super(Plugin, self).__init__(context=context)
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_INIT,
+    )
+    def _init(self):
+        self.environment.setdefault(
+            osetupcons.ProvisioningEnv.POSTGRES_CONF,
+            osetupcons.Defaults.DEFAULT_POSTGRES_PROVISIONING_PG_CONF
+        )
+        self.environment.setdefault(
+            osetupcons.ProvisioningEnv.POSTGRES_PG_HBA,
+            osetupcons.Defaults.DEFAULT_POSTGRES_PROVISIONING_PG_HBA
+        )
+        self.environment.setdefault(
+            osetupcons.ProvisioningEnv.POSTGRES_PG_VERSION,
+            osetupcons.Defaults.DEFAULT_POSTGRES_PROVISIONING_PG_VERSION
+        )
+        self.environment.setdefault(
+            osetupcons.ProvisioningEnv.POSTGRES_SERVICE,
+            osetupcons.Defaults.DEFAULT_POSTGRES_PROVISIONING_SERVICE
+        )
+        self.environment.setdefault(
+            osetupcons.ProvisioningEnv.POSTGRES_MAX_CONN,
+            osetupcons.Defaults.DEFAULT_POSTGRES_PROVISIONING_MAX_CONN
+        )
+
+
+# vim: expandtab tabstop=4 shiftwidth=4
diff --git 
a/packaging/setup/plugins/ovirt-engine-setup/ovirt-engine/provisioning/postgres.py
 
b/packaging/setup/plugins/ovirt-engine-setup/ovirt-engine/provisioning/postgres.py
index 3f676a0..f6441b1 100644
--- 
a/packaging/setup/plugins/ovirt-engine-setup/ovirt-engine/provisioning/postgres.py
+++ 
b/packaging/setup/plugins/ovirt-engine-setup/ovirt-engine/provisioning/postgres.py
@@ -19,345 +19,41 @@
 """Local Postgres plugin."""
 
 
-import os
-import platform
-import re
-import random
-import datetime
-import time
 import gettext
 _ = lambda m: gettext.dgettext(message=m, domain='ovirt-engine-setup')
 
 
 from otopi import util
-from otopi import transaction
-from otopi import filetransaction
 from otopi import plugin
-from otopi import constants as otopicons
 
 
 from ovirt_engine_setup import constants as osetupcons
-from ovirt_engine_setup import database
 from ovirt_engine_setup import dialog
-from ovirt_engine_setup import util as osetuputil
+from ovirt_engine_setup import postgres
 
 
 @util.export
 class Plugin(plugin.PluginBase):
     """Local Postgres plugin."""
 
-    _PASSWORD_CHARS = (
-        '0123456789' +
-        'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
-        'abcdefghijklmnopqrstuvwxyz'
-    )
-
-    _RE_POSTGRES_PGHBA_LOCAL = re.compile(
-        flags=re.VERBOSE,
-        pattern=r"""
-            ^
-            (?P<host>local)
-            \s+
-            .*
-            \s+
-            (?P<param>\w+)
-            $
-        """
-    )
-
-    class _alternateUser(object):
-        def __init__(self, user):
-            self._user = osetuputil.getUid(user)
-
-        def __enter__(self):
-            os.seteuid(self._user)
-
-        def __exit__(self, exc_type, exc_value, traceback):
-            os.seteuid(os.getuid())
-
-    def _generatePassword(self):
-        return ''.join([random.choice(self._PASSWORD_CHARS) for i in range(8)])
-
-    def _initDB(self):
-        self.logger.info(_('Initializing PostgreSQL'))
-
-        setup = self.command.get(
-            command='postgresql-setup',
-            optional=True
-        )
-        if setup is not None:
-            # new method (post-systemd)
-            self.execute(
-                (
-                    setup,
-                    'initdb',
-                ),
-            )
-        else:
-            # old method (pre-systemd)
-            self.execute(
-                (
-                    os.path.join(
-                        osetupcons.FileLocations.SYSCONFDIR,
-                        'init.d',
-                        self.environment[
-                            osetupcons.ProvisioningEnv.POSTGRES_SERVICE
-                        ],
-                    ),
-                    'initdb',
-                ),
-            )
-
-    def _updateMaxConnections(
-        self,
-        transaction,
-        filename,
-        maxconn,
-    ):
-        with open(filename, 'r') as f:
-            content = osetuputil.editConfigContent(
-                content=f.read().splitlines(),
-                params={
-                    'max_connections': maxconn,
-                },
-            )
-
-        transaction.append(
-            filetransaction.FileTransaction(
-                name=filename,
-                content=content,
-                modifiedList=self.environment[
-                    otopicons.CoreEnv.MODIFIED_FILES
-                ],
-            ),
-        )
-        self.environment[
-            osetupcons.CoreEnv.UNINSTALL_UNREMOVABLE_FILES
-        ].append(filename)
-
-    def _setPgHbaLocalPeer(
-        self,
-        transaction,
-        filename,
-    ):
-        content = []
-        with open(filename, 'r') as f:
-            for line in f.read().splitlines():
-                matcher = self._RE_POSTGRES_PGHBA_LOCAL.match(line)
-                if matcher is not None:
-                    line = line.replace(
-                        matcher.group('param'),
-                        'ident',  # we cannot use peer <psql-9
-                    )
-                content.append(line)
-
-        transaction.append(
-            filetransaction.FileTransaction(
-                name=filename,
-                content=content,
-                visibleButUnsafe=True,
-            )
-        )
-
-    def _addPgHbaDatabaseAccess(
-        self,
-        transaction,
-        filename,
-    ):
-        lines = [
-            # we cannot use all for address <psql-9
-            (
-                '{host:7} '
-                '{user:15} '
-                '{database:15} '
-                '{address:23} '
-                '{auth}'
-            ).format(
-                host='host',
-                user=self.environment[
-                    osetupcons.DBEnv.USER
-                ],
-                database=self.environment[
-                    osetupcons.DBEnv.DATABASE
-                ],
-                address=address,
-                auth='md5',
-            )
-            for address in ('0.0.0.0/0', '::0/0')
-        ]
-
-        content = []
-        with open(filename, 'r') as f:
-            for line in f.read().splitlines():
-                if line not in lines:
-                    content.append(line)
-
-                # order is important, add after local
-                # so we be first
-                if line.lstrip().startswith('local'):
-                    content.extend(lines)
-
-        transaction.append(
-            filetransaction.FileTransaction(
-                name=filename,
-                content=content,
-                modifiedList=self.environment[
-                    otopicons.CoreEnv.MODIFIED_FILES
-                ],
-            )
-        )
-        self.environment[
-            osetupcons.CoreEnv.UNINSTALL_UNREMOVABLE_FILES
-        ].append(filename)
-
-    def _waitDatabase(self, environment=None):
-        dbovirtutils = database.OvirtUtils(
-            plugin=self,
-            dbenvkeys=osetupcons.Const.ENGINE_DB_ENV_KEYS,
-        )
-        for i in range(60):
-            try:
-                self.logger.debug('Attempting to connect database')
-                dbovirtutils.tryDatabaseConnect(environment=environment)
-                break
-            except RuntimeError:
-                self.logger.debug(
-                    'Database connection failed',
-                    exc_info=True,
-                )
-                time.sleep(1)
-            except Exception:
-                self.logger.debug(
-                    'Database connection failed, unknown exception',
-                    exc_info=True,
-                )
-                raise
-
-    def _setDatabaseResources(self, environment):
-        dbstatement = database.Statement(
-            dbenvkeys=osetupcons.Const.ENGINE_DB_ENV_KEYS,
-            environment=environment,
-        )
-        hasDatabase = dbstatement.execute(
-            statement="""
-                select count(*) as count
-                from pg_database
-                where datname = %(database)s
-            """,
-            args=dict(
-                database=self.environment[
-                    osetupcons.DBEnv.DATABASE
-                ],
-            ),
-            ownConnection=True,
-            transaction=False,
-        )[0]['count'] != 0
-        hasUser = dbstatement.execute(
-            statement="""
-                select count(*) as count
-                from pg_user
-                where usename = %(user)s
-            """,
-            args=dict(
-                user=self.environment[
-                    osetupcons.DBEnv.USER
-                ],
-            ),
-            ownConnection=True,
-            transaction=False,
-        )[0]['count'] != 0
-
-        generate = hasDatabase or hasUser
-        existing = False
-
-        if hasDatabase and hasUser:
-            dbovirtutils = database.OvirtUtils(
-                plugin=self,
-                dbenvkeys=osetupcons.Const.ENGINE_DB_ENV_KEYS,
-                environment=environment,
-            )
-            if dbovirtutils.isNewDatabase(
-                database=self.environment[
-                    osetupcons.DBEnv.DATABASE
-                ],
-            ):
-                self.logger.debug('Found empty database')
-                generate = False
-                existing = True
-            else:
-                generate = True
-
-        if generate:
-            self.logger.debug('Existing resources found, generating names')
-            suffix = '_%s' % datetime.datetime.now().strftime('%Y%m%d%H%M%S')
-            self.environment[osetupcons.DBEnv.DATABASE] += suffix
-            self.environment[osetupcons.DBEnv.USER] += suffix
-            self._renamedDBResources = True
-
-        return existing
-
-    def _performDatabase(
-        self,
-        environment,
-        op,
-        user,
-        password,
-        databaseName,
-    ):
-        statements = [
-            (
-                """
-                    {op} role {user}
-                    with
-                        login
-                        encrypted password %(password)s
-                """
-            ).format(
-                op=op,
-                user=user,
-            ),
-
-            (
-                """
-                    {op} database {database}
-                    owner {to} {user}
-                    {encoding}
-                """
-            ).format(
-                op=op,
-                to='to' if op == 'alter' else '',
-                database=databaseName,
-                user=user,
-                encoding="""
-                    template template0
-                    encoding 'UTF8'
-                    lc_collate 'en_US.UTF-8'
-                    lc_ctype 'en_US.UTF-8'
-                """ if op != 'alter' else '',
-            ),
-        ]
-
-        dbstatement = database.Statement(
-            dbenvkeys=osetupcons.Const.ENGINE_DB_ENV_KEYS,
-            environment=environment,
-        )
-        for statement in statements:
-            dbstatement.execute(
-                statement=statement,
-                args=dict(
-                    password=password,
-                ),
-                ownConnection=True,
-                transaction=False,
-            )
-
     def __init__(self, context):
         super(Plugin, self).__init__(context=context)
         self._enabled = False
         self._renamedDBResources = False
-        self._distribution = platform.linux_distribution(
-            full_distribution_name=0
-        )[0]
+        self._provisioning = postgres.Provisioning(
+            plugin=self,
+            dbenvkeys=osetupcons.Const.ENGINE_DB_ENV_KEYS,
+            defaults={
+                'user': osetupcons.Defaults.DEFAULT_DB_USER,
+                'database': osetupcons.Defaults.DEFAULT_DB_DATABASE,
+                'port': osetupcons.Defaults.DEFAULT_DB_PORT,
+                'secured': osetupcons.Defaults.DEFAULT_DB_SECURED,
+                'hostValidation': (
+                    osetupcons.Defaults.
+                    DEFAULT_DB_SECURED_HOST_VALIDATION
+                ),
+            },
+        )
 
     @plugin.event(
         stage=plugin.Stages.STAGE_INIT,
@@ -366,26 +62,6 @@
         self.environment.setdefault(
             osetupcons.ProvisioningEnv.POSTGRES_PROVISIONING_ENABLED,
             None
-        )
-        self.environment.setdefault(
-            osetupcons.ProvisioningEnv.POSTGRES_CONF,
-            osetupcons.Defaults.DEFAULT_POSTGRES_PROVISIONING_PG_CONF
-        )
-        self.environment.setdefault(
-            osetupcons.ProvisioningEnv.POSTGRES_PG_HBA,
-            osetupcons.Defaults.DEFAULT_POSTGRES_PROVISIONING_PG_HBA
-        )
-        self.environment.setdefault(
-            osetupcons.ProvisioningEnv.POSTGRES_PG_VERSION,
-            osetupcons.Defaults.DEFAULT_POSTGRES_PROVISIONING_PG_VERSION
-        )
-        self.environment.setdefault(
-            osetupcons.ProvisioningEnv.POSTGRES_SERVICE,
-            osetupcons.Defaults.DEFAULT_POSTGRES_PROVISIONING_SERVICE
-        )
-        self.environment.setdefault(
-            osetupcons.ProvisioningEnv.POSTGRES_MAX_CONN,
-            osetupcons.Defaults.DEFAULT_POSTGRES_PROVISIONING_MAX_CONN
         )
 
     @plugin.event(
@@ -403,13 +79,12 @@
         ),
     )
     def _setup(self):
-        self.command.detect('postgresql-setup')
+        self._provisioning.detectCommands()
 
-        self._enabled = self._distribution in ('redhat', 'fedora', 'centos')
+        self._enabled = self._provisioning.supported()
 
     @plugin.event(
         stage=plugin.Stages.STAGE_CUSTOMIZATION,
-        name=osetupcons.Stages.DB_HOST_LOCATION_CUSTOMIZATION,
         before=(
             osetupcons.Stages.DIALOG_TITLES_E_DATABASE,
             osetupcons.Stages.DB_CONNECTION_CUSTOMIZATION,
@@ -427,7 +102,8 @@
                 dialog=self.dialog,
                 name='OVESETUP_PROVISIONING_POSTGRES_LOCATION',
                 note=_(
-                    'Where is the database located? (@VALUES@) [@DEFAULT@]: '
+                    'Where is the Engine database located? '
+                    '(@VALUES@) [@DEFAULT@]: '
                 ),
                 prompt=True,
                 true=_('Local'),
@@ -453,7 +129,8 @@
                         'automatically for the engine to run. This may '
                         'conflict with existing applications.\n'
                         'Would you like Setup to automatically configure '
-                        'postgresql, or prefer to perform that '
+                        'postgresql and create Engine database, '
+                        'or prefer to perform that '
                         'manually? (@VALUES@) [@DEFAULT@]: '
                     ),
                     prompt=True,
@@ -462,51 +139,18 @@
                     default=True,
                 )
 
-        self._enabled = self.environment[
+        if self.environment[
             osetupcons.ProvisioningEnv.POSTGRES_PROVISIONING_ENABLED
-        ]
-
-        if self._enabled:
-
-            self.environment[
-                osetupcons.DBEnv.USER
-            ] = osetupcons.Defaults.DEFAULT_DB_USER
-
-            self.environment[
-                osetupcons.DBEnv.PASSWORD
-            ] = self._generatePassword()
-
-            self.environment[otopicons.CoreEnv.LOG_FILTER].append(
-                self.environment[
-                    osetupcons.DBEnv.PASSWORD
-                ]
-            )
-
-            self.environment[
-                osetupcons.DBEnv.DATABASE
-            ] = osetupcons.Defaults.DEFAULT_DB_DATABASE
-
-            self.environment[
-                osetupcons.DBEnv.SECURED
-            ] = osetupcons.Defaults.DEFAULT_DB_SECURED
-
-            self.environment[
-                osetupcons.DBEnv.SECURED_HOST_VALIDATION
-            ] = osetupcons.Defaults.DEFAULT_DB_SECURED_HOST_VALIDATION
+        ]:
+            self._provisioning.applyEnvironment()
+            self._enabled = True
 
     @plugin.event(
         stage=plugin.Stages.STAGE_CUSTOMIZATION,
-        before=(
-            osetupcons.Stages.DIALOG_TITLES_E_DATABASE,
-            osetupcons.Stages.DB_CONNECTION_CUSTOMIZATION,
-        ),
-        after=(
-            osetupcons.Stages.DIALOG_TITLES_S_DATABASE,
-            osetupcons.Stages.DB_HOST_LOCATION_CUSTOMIZATION,
-        ),
-        condition=lambda self: (
-            self.environment[osetupcons.DBEnv.HOST] == 'localhost'
-        )
+        priority=plugin.Stages.PRIORITY_LAST,
+        condition=lambda self: self.environment[
+            osetupcons.DBEnv.HOST
+        ] == 'localhost',
     )
     def _customization_firewall(self):
         self.environment[osetupcons.NetEnv.FIREWALLD_SERVICES].extend([
@@ -521,19 +165,7 @@
         condition=lambda self: self._enabled,
     )
     def _validation(self):
-        if not self.services.exists(
-            name=self.environment[
-                osetupcons.ProvisioningEnv.POSTGRES_SERVICE
-            ]
-        ):
-            raise RuntimeError(
-                _(
-                    'Database configuration was requested, '
-                    'however, postgresql service was not found. '
-                    'This may happen because postgresql database '
-                    'is not installed on system.'
-                )
-            )
+        self._provisioning.validate()
 
     @plugin.event(
         stage=plugin.Stages.STAGE_MISC,
@@ -547,112 +179,7 @@
         condition=lambda self: self._enabled,
     )
     def _misc(self):
-
-        if not os.path.exists(
-            self.environment[
-                osetupcons.ProvisioningEnv.POSTGRES_PG_VERSION
-            ]
-        ):
-            self._initDB()
-
-        self.logger.info(_('Creating PostgreSQL database'))
-        localtransaction = transaction.Transaction()
-        try:
-            localtransaction.prepare()
-
-            self._setPgHbaLocalPeer(
-                transaction=localtransaction,
-                filename=self.environment[
-                    osetupcons.ProvisioningEnv.POSTGRES_PG_HBA
-                ],
-            )
-
-            # restart to take effect
-            for state in (False, True):
-                self.services.state(
-                    name=self.environment[
-                        osetupcons.ProvisioningEnv.POSTGRES_SERVICE
-                    ],
-                    state=state,
-                )
-
-            with self._alternateUser(
-                user=self.environment[
-                    osetupcons.SystemEnv.USER_POSTGRES
-                ],
-            ):
-                usockenv = {
-                    osetupcons.DBEnv.HOST: '',  # usock
-                    osetupcons.DBEnv.PORT: '',
-                    osetupcons.DBEnv.SECURED: False,
-                    osetupcons.DBEnv.SECURED_HOST_VALIDATION: False,
-                    osetupcons.DBEnv.USER: 'postgres',
-                    osetupcons.DBEnv.PASSWORD: '',
-                    osetupcons.DBEnv.DATABASE: 'template1',
-                }
-                self._waitDatabase(
-                    environment=usockenv,
-                )
-                existing = self._setDatabaseResources(
-                    environment=usockenv,
-                )
-                self._performDatabase(
-                    environment=usockenv,
-                    op=(
-                        'alter' if existing
-                        else 'create'
-                    ),
-                    user=self.environment[
-                        osetupcons.DBEnv.USER
-                    ],
-                    password=self.environment[
-                        osetupcons.DBEnv.PASSWORD
-                    ],
-                    databaseName=self.environment[
-                        osetupcons.DBEnv.DATABASE
-                    ],
-                )
-        finally:
-            # restore everything
-            localtransaction.abort()
-
-        self.logger.info(_('Configuring PostgreSQL'))
-        localtransaction = transaction.Transaction()
-        with localtransaction:
-            self._addPgHbaDatabaseAccess(
-                transaction=localtransaction,
-                filename=self.environment[
-                    osetupcons.ProvisioningEnv.POSTGRES_PG_HBA
-                ],
-            )
-
-            self._updateMaxConnections(
-                transaction=localtransaction,
-                filename=self.environment[
-                    osetupcons.ProvisioningEnv.POSTGRES_CONF
-                ],
-                maxconn=self.environment[
-                    osetupcons.ProvisioningEnv.POSTGRES_MAX_CONN
-                ],
-            )
-
-        # restart to take effect
-        for state in (False, True):
-            self.services.state(
-                name=self.environment[
-                    osetupcons.ProvisioningEnv.POSTGRES_SERVICE
-                ],
-                state=state,
-            )
-
-        self.services.startup(
-            name=self.environment[
-                osetupcons.ProvisioningEnv.POSTGRES_SERVICE
-            ],
-            state=True,
-        )
-
-        self._waitDatabase()
+        self._provisioning.provision()
 
     @plugin.event(
         stage=plugin.Stages.STAGE_CLOSEUP,
@@ -662,12 +189,12 @@
         after=(
             osetupcons.Stages.DIALOG_TITLES_S_SUMMARY,
         ),
-        condition=lambda self: self._renamedDBResources,
+        condition=lambda self: self._provisioning.databaseRenamed,
     )
     def _closeup(self):
         self.dialog.note(
             text=_(
-                'Database resources:\n'
+                'Engine database resources:\n'
                 '    Database name:      {database}\n'
                 '    Database user name: {user}\n'
             ).format(


-- 
To view, visit http://gerrit.ovirt.org/23121
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ieff824fa5115954925f8fd7cabf59d535f39e96c
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Alon Bar-Lev <[email protected]>
_______________________________________________
Engine-patches mailing list
[email protected]
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to