depot.py revision 751
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# pkg.depotd - package repository daemon
# XXX The prototype pkg.depotd combines both the version management server that
# answers to pkgsend(1) sessions and the HTTP file server that answers to the
# various GET operations that a pkg(1) client makes. This split is expected to
# be made more explicit, by constraining the pkg(1) operations such that they
# operations, and must manipulate the various state files--catalogs, in
# particular--such that the pkg(1) pull client can operately accurately with
# XXX We should support simple "last-modified" operations via HEAD queries.
# XXX Although we pushed the evaluation of next-version, etc. to the pull
# client, we should probably provide a query API to do same on the server, for
# dumb clients (like a notification service).
# The default authority for the depot.
AUTH_DEFAULT = "opensolaris.org"
# The default repository path.
REPO_PATH_DEFAULT = "/var/pkg/repo"
# The default path for static and other web content.
CONTENT_PATH_DEFAULT = "/usr/share/lib/pkg"
# The default port to serve data from.
PORT_DEFAULT = 80
# The minimum number of threads allowed.
THREADS_MIN = 1
# The default number of threads to start.
THREADS_DEFAULT = 10
# The maximum number of threads that can be started.
THREADS_MAX = 100
# The default server socket timeout in seconds. We want this to be longer than
# the normal default of 10 seconds to accommodate clients with poor quality
# connections.
# Whether modify operations should be allowed.
# Whether the repository catalog should be rebuilt on startup.
# Whether the indexes should be rebuilt
# Not in mirror mode by default
import getopt
import gettext
import locale
import logging
import os
import sys
import urlparse
try:
import cherrypy
raise ImportError
raise ImportError
except ImportError:
"""3.2.0) is required to use this program."""
"""This is a dummy object that we can use to discard log entries
"""Discard the bits."""
pass
"""Discard the bits."""
pass
if text:
print """\
Usage: /usr/lib/pkg.depotd [-d repo_dir] [-p port] [-s threads]
[-t socket_timeout] [--content-root] [--log-access dest]
[--log-errors dest] [--mirror] [--proxy-base url] [--readonly]
[--rebuild]
--content-root The file system path to the directory containing the
the static and other web content used by the depot's
browser user interface. The default value is
--log-access The destination for any access related information
logged by the depot process. Possible values are:
stderr, stdout, none, or an absolute pathname. The
default value is stdout if stdout is a tty; otherwise
the default value is none.
--log-errors The destination for any errors or other information
logged by the depot process. Possible values are:
stderr, stdout, none, or an absolute pathname. The
default value is stderr.
--mirror Package mirror mode; publishing and metadata operations
disallowed. Cannot be used with --readonly or
--rebuild.
--proxy-base The url to use as the base for generating internal
redirects and content.
--readonly Read-only operation; modifying operations disallowed.
Cannot be used with --mirror or --rebuild.
--rebuild Re-build the catalog from pkgs in depot. Cannot be
used with --mirror or --readonly.
"""
class OptionError(Exception):
"""Option exception. """
if __name__ == "__main__":
proxy_base = None
else:
try:
except KeyError:
try:
except KeyError:
# By default, if the destination for a particular log type is not
# specified, this is where we will send the output.
log_routes = {
"access": "none",
"errors": "stderr"
}
# If stdout is a tty, then send access output there by default instead
# of discarding it.
opt = None
try:
"readonly", "rebuild", "refresh-index"]
if opt == "-n":
elif opt == "-d":
elif opt == "-p":
elif opt == "-s":
if threads < THREADS_MIN:
raise OptionError, \
"minimum value is %d" % THREADS_MIN
if threads > THREADS_MAX:
raise OptionError, \
"maximum value is %d" % THREADS_MAX
elif opt == "-t":
elif opt == "--content-root":
if arg == "":
raise OptionError, "You must specify " \
"a directory path."
raise OptionError, \
"You must specify a log " \
"destination."
elif opt == "--mirror":
elif opt == "--proxy-base":
# Attempt to decompose the url provided into
# its base parts. This is done so we can
# remove any scheme information since we
# don't need it.
# Rebuild the url without the scheme and
# remove the leading // urlunparse adds.
).lstrip("//")
elif opt == "--readonly":
elif opt == "--rebuild":
elif opt == "--refresh-index":
# Note: This argument is for internal use
# only. It's used when pkg.depotd is reexecing
# itself and needs to know that's the case.
# This flag is purposefully omitted in usage.
# The supported way to forcefully reindex is to
# kill any pkg.depot using that directory,
# remove the index directory, and restart the
# pkg.depot process. The index will be rebuilt
# automatically on startup.
except getopt.GetoptError, e:
except OptionError, e:
except (ArithmeticError, ValueError):
usage("pkg.depotd: illegal option value: %s specified " \
usage("--refresh-index cannot be used with --rebuild")
usage("--readonly and --mirror cannot be used with --rebuild")
usage("--readonly and --mirror cannot be used with " \
"--refresh-index")
# If the program is going to reindex, the port is irrelevant since
# the program will not bind to a port.
if not reindex:
if not available:
print "pkg.depotd: unable to bind to the specified " \
else:
# Not applicable for reindexing operations.
content_root = None
if rebuild:
if readonly:
if mirror:
try:
except (RuntimeError, EnvironmentError), e:
print "pkg.depotd: an error occurred while trying to " \
"initialize the depot repository directory " \
"structures:\n%s" % e
# Setup our global configuration.
# Global cherrypy configuration
gconf = {
"environment": "production",
"checker.on": True,
"log.screen": False,
"server.socket_host": "0.0.0.0",
"server.socket_port": port,
"server.thread_pool": threads,
"server.socket_timeout": socket_timeout,
"tools.log_headers.on": True,
"tools.encode.on": True
}
log_type_map = {
"errors": {
"param": "log.error_file",
"attr": "error_log"
},
"access": {
"param": "log.access_file",
"attr": "access_log"
}
}
for log_type in log_type_map:
if dest == "none":
else:
dest))
# Since we've replaced cherrypy's log handler with our
# own, we don't want the output directed to a file.
dest = ""
# Now that our logging, etc. has been setup, it's safe to perform any
# remaining preparation.
if reindex:
try:
except search_errors.IndexingException, e:
# Now build our site configuration.
conf = {
"/": {
# We have to override cherrypy's default response_class so that
# we have access to the write() callable to stream data
# directly to the client.
},
"/robots.txt": {
"tools.staticfile.on": True,
"robots.txt")
},
}
if proxy_base:
# This changes the base URL for our server, and is primarily
# intended to allow our depot process to operate behind Apache
# or some other webserver process.
#
# Visit the following URL for more information:
# http://cherrypy.org/wiki/BuiltinTools#tools.proxy
proxy_conf = {
"tools.proxy.on": True,
"tools.proxy.local": "",
"tools.proxy.base": proxy_base
}
# Now merge or add our proxy configuration information into the
# existing configuration.
for entry in proxy_conf:
try:
except rc.InvalidAttributeValueError, e:
emsg("pkg.depotd: repository.conf error: %s" % e)
try:
except Exception:
usage("pkg.depotd: unknown error starting depot, illegal " \
"option value specified?")