# $SnapHashLicense:
#
# SnapLogic - Open source data services
#
# Copyright (C) 2008 - 2009 SnapLogic, Inc. All rights reserved.
#
# See http://www.snaplogic.org for more information about
# the SnapLogic project.
#
# This program is free software, distributed under the terms of
# the GNU General Public License Version 2. See the LEGAL file
# at the top of the source tree.
#
# "SnapLogic" is a trademark of SnapLogic, Inc.
#
#
# $
# $Id: __init__.py 9868 2009-11-21 17:50:45Z dhiraj $
from __future__ import with_statement
"""
This package contains functionality for managing storage of resources with various backend databases.
"""
__docformat__ = "epytext en"
import os
import uuid
import threading
import errno
from snaplogic.common.snap_exceptions import *
from snaplogic.common import snap_log,version_info
from snaplogic.common.config import snap_config
from snaplogic.snapi_base import keys
from snaplogic.server.repository.request_proxy import RequestProxy
from snaplogic.server.repository import reg_keys,version_history
_store = None
_mutex = threading.Lock()
repo_log = None
repo_log = None
def get_instance():
"""
Get a new instance of the loaded repository.
A new proxy object instance is created to wrap the internal store with the public API used for accessing
the repository in the main process.
@return: A new instance to the loaded repository to use.
@rtype: RequestProxy
@raises SnapRepInitError: Repository not initialized.
"""
with _mutex:
if _store is not None:
return RequestProxy(_store.clone(), repo_log)
else:
raise SnapRepInitError("Repository not initialized.")
def init():
"""
Initialize the repository.
The config file must be loaded and useable before this method is called. The [repository] section is
examined in the config and the database loaded.
@raise SnapRepInitError: There was an error parsing the config or there was an error connecting or validating
the store contained within the database.
"""
global repo_log, repo_elog, _store
if _store is not None:
raise SnapRepInitError("Repository already initialized.")
config = snap_config.get_instance()
main_config = config.get_section('main')
(repo_log, repo_elog, ignore_rlog) = snap_log.get_instance().make_specific_loggers(snap_log.LOG_REPO)
try:
try:
repo_config = config.get_section('repository')
except SnapObjNotFoundError, e:
raise SnapException.chain(e, SnapRepInitError("Repository section missing in config file."))
_store = connect_store(repo_config)
repo_log(snap_log.LEVEL_INFO, "Connected to repository.")
except SnapRepError, e:
repo_elog(e)
raise
except Exception, e:
new_e = SnapException.chain(e, SnapRepInitError("Repository internal initialization failure: " + str(e)))
repo_elog(new_e)
raise new_e
def connect_store(repo_config, perform_checks=True):
"""
Initialize a SnapStore object from the repository config.
@param repo_config: A dictionary of repository parameters like those found in the [repository] section.
@type repo_config: dict
@param perform_checks: If true, perform some checks to insure the integrity of the repo. Should be off for upgrade.
@type perform_checks: bool
@return: Initialized SnapStore object.
@rtype: L{snaplogic.server.repository.snap_store.SnapStore}
@raises SnapRepInitError: Unable to open repository or invalid parameters specified.
"""
repo_type = repo_config.get('type', None)
if repo_type == 'sqlite':
store = _init_sqlite(repo_config)
elif repo_type == 'mysql':
store = _init_mysql(repo_config)
else:
raise SnapRepInitError("Unsupported repository type '%s'." % repo_type)
# Check the designated version for another lock. If the lock was held by an older version, update
# it to the current server's version.
if perform_checks:
check_store_integrity(store)
return store
def _init_sqlite(repo_config):
"""
Initialize an SQLite store from the repository config.
@param repo_config: The [repository] section of the config.
@type repo_config: dict
@return: A SnapStore object connected to the database specified in repo_config.
@rtype: L{snaplogic.server.repository.snap_store.SnapStore}
@raises SnapRepInitError: Error reading config or loading or verifying the repository database.
"""
db_path = repo_config.get('path', None)
if db_path is None:
raise SnapRepInitError("SQLite repository requires path for DB file")
from snaplogic.server.repository.sqlite import SQLite
store = SQLite()
store.connect(db_path)
return store
def _init_mysql(repo_config):
"""
Initialize a MySQL store from the repository config.
@param repo_config: The [repository] section of the config.
@type repo_config: dict
@return: A SnapStore object connected to the database specified in repo_config.
@rtype: L{snaplogic.server.repository.snap_store.SnapStore}
@raises SnapRepInitError: Error reading config or loading or verifying the repository database.
"""
for key in ["host", "db", "user"]:
if key not in repo_config or repo_config[key] is None:
raise SnapRepInitError("Repository section missing required MySQL entry '%s'" % key)
if 'port' in repo_config:
port = int(repo_config['port'])
else:
port = None
passwd = repo_config.get('password', '')
from snaplogic.server.repository.mysql import MySQL
store = MySQL()
store.connect(repo_config['host'], port, repo_config['db'], repo_config['user'], passwd)
return store
def check_store_integrity(store):
"""
Check the integrity of the store.
The first value checked is the DB schema (format) version. If this value is not exactly equal to
the server repository version, an appropriate error is raised.
If the version designation lock in the store is less than this server's version, it will be updated
to this server's value. If the stored version is greater than this server, the repository initialization
will be aborted. If they are equal, the store is left as is and repository initialization is allowed
to complete.
@param store: A repository store object.
@type: L{snaplogic.server.repository.snap_store.SnapStore}
@raises SnapRepInitError: Validation failed.
"""
format_version = store.read_version()
if format_version < version_info.repository_version:
raise SnapRepInitError("Repository format version (%s) requires upgrade before starting server" %
format_version)
elif format_version > version_info.repository_version:
raise SnapRepInitError("Repository format version (%s) incompatible with this server version" %
format_version)
designated_version = store.read_designated_version()
if designated_version != version_info.server_version:
parsed_designated = designated_version.split('.')
parsed_server = version_info.server_version.split('.')
if len(parsed_designated) != len(parsed_server):
raise SnapRepInitError("Version number parsing error: incompatible version number formats")
for i in xrange(len(parsed_designated)):
if parsed_designated[i] > parsed_server[i]:
raise SnapRepInitError("Repository designated version (%s) greater than server version (%s)" %
(designated_version, version_info.server_version))
elif parsed_designated[i] < parsed_server[i]:
# Update the designation value.
store.set_designated_version(version_info.server_version)
if repo_log is not None:
repo_log(snap_log.LEVEL_INFO,
"Updating repository designated version to " + version_info.server_version)
break
|