depot.py revision 260
#
# 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).
import BaseHTTPServer
import SocketServer
import socket
import errno
import getopt
import os
import re
import sys
import urllib
import tarfile
import cgi
import traceback
import httplib
def usage():
print """\
Usage: /usr/lib/pkg.depotd [--readonly] [--rebuild] [-d repo_dir] [-p port]
--readonly Read-only operation; modifying operations disallowed
--rebuild Re-build the catalog from pkgs in depot
"""
) + "\n"
try:
except IndexError:
return
if not token:
return
if not scfg.search_available():
return
try:
except KeyError:
return
for l in res:
# Try to guard against a non-existent catalog. The catalog open will
# raise an exception, and only the attributes will have been sent. But
# because we've sent data already (never mind the response header), we
# can't raise an exception here, or an INTERNAL_SERVER_ERROR header
# will get sent as well.
try:
except:
"""The request is an encoded pkg FMRI. If the version is specified
incompletely, we return an error, as the client is expected to form
correct requests, based on its interpretation of the catalog and its
image policies."""
# Parse request into FMRI component and decode.
# Open manifest and send.
try:
except IOError, e:
else:
return
"""Request data contains application/x-www-form-urlencoded entries
with the requested filenames."""
# If the sender doesn't specify the content length, reject this request.
# Calling read() with no size specified will force the server to block
# until the client sends EOF, an undesireable situation
if size == 0:
return
# If the sender doesn't specify the content length, reject this request.
# Calling read() with no size specified will force the server to block
# until the client sends EOF, an undesireable situation
if size == 0:
return
try:
except KeyError:
return
except ValueError:
return
try:
except KeyError:
return
except ValueError:
return
try:
except catalog.CatalogException, e:
return
except catalog.RenameException, e:
return
"""The request is the SHA-1 hash name for the file."""
try:
except IOError, e:
else:
return
# XXX Authentication will be handled by virtue of possessing a signed
# certificate (or a more elaborate system).
if scfg.is_read_only():
return
t = trans.Transaction()
else:
if scfg.is_read_only():
return
# Pull transaction ID from headers.
try:
except KeyError:
else:
if scfg.is_read_only():
return
# Pull transaction ID from headers.
try:
except KeyError:
else:
if scfg.is_read_only():
return
try:
except KeyError:
else:
else:
def set_ops():
vops = {}
if not m:
continue
else:
return vops
def address_string(self):
return host
else:
return
# Make sure that we have a integer protocol version
try:
except IndexError, e:
return
except ValueError, e:
return
# If we get here, we know that 'operation' is supported.
# Assume 'version' is not supported for that operation.
vns = "Version '%s' not supported for operation '%s'\n"
return
try:
exec op_call
except:
# XXX op_call may already have spit some data out to the
# client, in which case this response just corrupts that
# datastream. I don't know of any way to tell whether
# data has already been sent.
pass
vops = {}
if __name__ == "__main__":
port = 80
unprivport = 10000
try:
["readonly", "rebuild"])
if opt == "-n":
elif opt == "-d":
elif opt == "-p":
elif opt == "--readonly":
elif opt == "--rebuild":
except getopt.GetoptError, e:
print "pkg.depotd: illegal option -- %s" % e.opt
usage()
try:
raise
"Insufficient privilege to bind to port %d." % port
"Bound server to port %d instead." % unprivport
"Use the -p option to pick another port, if desired."