Skip to content
This repository has been archived by the owner on Dec 7, 2022. It is now read-only.
/ pulp Public archive

Commit

Permalink
1080609 - pulp-manage-db now ensures the admin.
Browse files Browse the repository at this point in the history
The webserver used to create the admin role and user if it didn't exist
upon startup. Once Pulp started to be deployed to multiple processes,
this caused a uniqueness constraint to be raised during the first
startup of Apache, as each process raced to create the admin user
simultaneously.

This commit moves the admin role and user creation into the
pulp-manage-db script.

https://bugzilla.redhat.com/show_bug.cgi?id=1080609
  • Loading branch information
Randy Barlow committed Apr 17, 2014
1 parent 666baa2 commit 8ace3d6
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 57 deletions.
28 changes: 24 additions & 4 deletions server/pulp/server/db/manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
from pulp.server import logs
from pulp.server.db import connection
from pulp.server.db.migrate import models
from pulp.server.managers import factory
from pulp.server.managers.auth.role.cud import RoleManager
from pulp.server.managers.auth.user.cud import UserManager


connection.initialize()
Expand Down Expand Up @@ -58,14 +61,15 @@ def migrate_database(options):
migration_packages = models.get_migration_packages()
for migration_package in migration_packages:
if migration_package.current_version > migration_package.latest_available_version:
msg = _('The database for migration package %(p)s is at version %(v)s, which is larger than the '
'latest version available, %(a)s.')
msg = _('The database for migration package %(p)s is at version %(v)s, which is larger '
'than the latest version available, %(a)s.')
msg = msg % ({'p': migration_package.name, 'v': migration_package.current_version,
'a': migration_package.latest_available_version})
raise DataError(msg)
if migration_package.current_version == migration_package.latest_available_version:
message = _('Migration package %(p)s is up to date at version %(v)s')
message = message % {'p': migration_package.name, 'v': migration_package.latest_available_version}
message = message % {'p': migration_package.name,
'v': migration_package.latest_available_version}
logger.info(message)
print message
continue
Expand All @@ -81,7 +85,8 @@ def migrate_database(options):
migration_package.apply_migration(migration,
update_current_version=not options.test)
message = _('Migration to %(p)s version %(v)s complete.')
message = message % {'p': migration_package.name, 'v': migration_package.current_version}
message = message % {'p': migration_package.name,
'v': migration_package.current_version}
print message
logger.info(message)
except Exception, e:
Expand Down Expand Up @@ -117,6 +122,7 @@ def main():
logger.critical(str(e))
logger.critical(''.join(traceback.format_exception(*sys.exc_info())))
return os.EX_SOFTWARE
return os.EX_OK


def _auto_manage_db(options):
Expand All @@ -134,6 +140,20 @@ def _auto_manage_db(options):
print message
logger.info(message)

message = _('Ensuring the admin role and user are in place.')
print message
logger.info(message)
# Due to the silliness of the factory, we have to initialize it because the UserManager and
# RoleManager are going to try to use it.
factory.initialize()
role_manager = RoleManager()
role_manager.ensure_super_user_role()
user_manager = UserManager()
user_manager.ensure_admin()
message = _('Admin role and user are in place.')
print message
logger.info(message)

message = _('Beginning database migrations.')
print message
logger.info(message)
Expand Down
36 changes: 18 additions & 18 deletions server/pulp/server/managers/auth/role/cud.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@


SUPER_USER_ROLE = 'super-users'
_ROLE_NAME_REGEX = re.compile(r'^[\-_A-Za-z0-9]+$') # letters, numbers, underscore, hyphen
_ROLE_NAME_REGEX = re.compile(r'^[\-_A-Za-z0-9]+$') # letters, numbers, underscore, hyphen


class RoleManager(object):
Expand All @@ -51,7 +51,7 @@ def create_role(role_id, display_name=None, description=None):
:raise DuplicateResource: if there is already a role with the requested name
:raise InvalidValue: if any of the fields are unacceptable
"""
existing_role = Role.get_collection().find_one({'id' : role_id})
existing_role = Role.get_collection().find_one({'id': role_id})
if existing_role is not None:
raise DuplicateResource(role_id)

Expand All @@ -66,7 +66,7 @@ def create_role(role_id, display_name=None, description=None):
Role.get_collection().save(create_me, safe=True)

# Retrieve the role to return the SON object
created = Role.get_collection().find_one({'id' : role_id})
created = Role.get_collection().find_one({'id': role_id})

return created

Expand All @@ -86,7 +86,7 @@ def update_role(role_id, delta):
"""
delta.pop('id', None)

role = Role.get_collection().find_one({'id' : role_id})
role = Role.get_collection().find_one({'id': role_id})
if role is None:
raise MissingResource(role_id)

Expand All @@ -109,7 +109,7 @@ def update_role(role_id, delta):
def delete_role(role_id):
"""
Deletes the given role. This has the side-effect of revoking any permissions granted
to the role from the users in the role, unless those permissions are also granted
to the role from the users in the role, unless those permissions are also granted
through another role the user is a memeber of.
:param role_id: identifies the role being deleted
Expand All @@ -122,7 +122,7 @@ def delete_role(role_id):
raise InvalidValue(['role_id'])

# Check whether role exists
role = Role.get_collection().find_one({'id' : role_id})
role = Role.get_collection().find_one({'id': role_id})
if role is None:
raise MissingResource(role_id)

Expand All @@ -142,12 +142,12 @@ def delete_role(role_id):
user['roles'].remove(role_id)
factory.user_manager().update_user(user['login'], Delta(user, 'roles'))

Role.get_collection().remove({'id' : role_id}, safe=True)
Role.get_collection().remove({'id': role_id}, safe=True)

@staticmethod
def add_permissions_to_role(role_id, resource, operations):
"""
Add permissions to a role.
Add permissions to a role.
:param role_id: role identifier
:type role_id: str
Expand Down Expand Up @@ -179,8 +179,8 @@ def add_permissions_to_role(role_id, resource, operations):
@staticmethod
def remove_permissions_from_role(role_id, resource, operations):
"""
Remove permissions from a role.
Remove permissions from a role.
:param role_id: role identifier
:type role_id: str
:param resource: resource path to revoke permissions from
Expand All @@ -192,7 +192,7 @@ def remove_permissions_from_role(role_id, resource, operations):
if role_id == SUPER_USER_ROLE:
raise PulpDataException(_('super-users role cannot be changed'))

role = Role.get_collection().find_one({'id' : role_id})
role = Role.get_collection().find_one({'id': role_id})
if role is None:
raise MissingResource(role_id)

Expand Down Expand Up @@ -223,7 +223,7 @@ def add_user_to_role(role_id, login):
"""
Add a user to a role. This has the side-effect of granting all the
permissions granted to the role to the user.
:param role_id: role identifier
:type role_id: str
:param login: login of user
Expand All @@ -232,11 +232,11 @@ def add_user_to_role(role_id, login):
:rtype: bool
:raise MissingResource: if the given role or user does not exist
"""
role = Role.get_collection().find_one({'id' : role_id})
role = Role.get_collection().find_one({'id': role_id})
if role is None:
raise MissingResource(role_id)

user = User.get_collection().find_one({'login' : login})
user = User.get_collection().find_one({'login': login})
if user is None:
raise MissingResource(login)

Expand All @@ -255,7 +255,7 @@ def remove_user_from_role(role_id, login):
Remove a user from a role. This has the side-effect of revoking all the
permissions granted to the role from the user, unless the permissions are
also granted by another role.
:param role_id: role identifier
:type role_id: str
:param login: name of user
Expand All @@ -264,11 +264,11 @@ def remove_user_from_role(role_id, login):
:rtype: bool
:raise MissingResource: if the given role or user does not exist
"""
role = Role.get_collection().find_one({'id' : role_id})
role = Role.get_collection().find_one({'id': role_id})
if role is None:
raise MissingResource(role_id)

user = User.get_collection().find_one({'login' : login})
user = User.get_collection().find_one({'login': login})
if user is None:
raise MissingResource(login)

Expand All @@ -294,7 +294,7 @@ def ensure_super_user_role(self):
"""
Ensure that the super user role exists.
"""
role = Role.get_collection().find_one({'id' : SUPER_USER_ROLE})
role = Role.get_collection().find_one({'id': SUPER_USER_ROLE})
if role is None:
role = self.create_role(SUPER_USER_ROLE, 'Super Users',
'Role indicates users with admin privileges')
Expand Down
26 changes: 11 additions & 15 deletions server/pulp/server/webservices/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,28 @@
import logging
import sys

# This keeps the web.py wsgi app from trying to handle otherwise unhandled
# exceptions and lets Pulp error handling middleware handle them instead
# This exists here as it is the first place that Pulp imports web.py, so all
# web.py applications will be instantiated *after* their base class is patched

def _handle_with_processors(self):
"""
This keeps the web.py wsgi app from trying to handle otherwise unhandled
exceptions and lets Pulp error handling middleware handle them instead
This exists here as it is the first place that Pulp imports web.py, so all
web.py applications will be instantiated *after* their base class is patched
"""
def process(processors):
if processors:
p, processors = processors[0], processors[1:]
return p(lambda : process(processors))
return p(lambda: process(processors))
else:
return self.handle()
return process(self.processors)


import web

web.application.handle_with_processors = _handle_with_processors

from pulp.server import config # automatically loads config
from pulp.server import config # automatically loads config
from pulp.server import logs

# We need to read the config, start the logging, and initialize the db
Expand All @@ -40,7 +44,6 @@ def process(processors):

from pulp.server.agent.direct.services import Services as AgentServices
from pulp.server.debugging import StacktraceDumper
from pulp.server.managers import factory as manager_factory
from pulp.server.db.migrate import models as migration_models
from pulp.server.webservices.controllers import (
agent, consumer_groups, consumers, contents, dispatch, events, permissions,
Expand Down Expand Up @@ -73,7 +76,6 @@ def process(processors):

STACK_TRACER = None

# -- initialization -----------------------------------------------------------

def _initialize_pulp():

Expand All @@ -99,7 +101,7 @@ def _initialize_pulp():
try:
migration_models.check_package_versions()
except Exception:
msg = 'The database has not been migrated to the current version. '
msg = 'The database has not been migrated to the current version. '
msg += 'Run pulp-manage-db and restart the application.'
raise initialization.InitializationException(msg), None, sys.exc_info()[2]

Expand All @@ -108,12 +110,6 @@ def _initialize_pulp():
# something gone horribly wrong. As such, I'm not going to account for each
# and instead simply let the exception itself bubble up.

# Ensure the minimal auth configuration
role_manager = manager_factory.role_manager()
role_manager.ensure_super_user_role()
user_manager = manager_factory.user_manager()
user_manager.ensure_admin()

# start agent services
AgentServices.start()

Expand Down

0 comments on commit 8ace3d6

Please sign in to comment.