depot.py revision 23
3177N/A#!/usr/bin/python
290N/A#
290N/A# CDDL HEADER START
290N/A#
290N/A# The contents of this file are subject to the terms of the
290N/A# Common Development and Distribution License (the "License").
290N/A# You may not use this file except in compliance with the License.
290N/A#
290N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
290N/A# or http://www.opensolaris.org/os/licensing.
290N/A# See the License for the specific language governing permissions
290N/A# and limitations under the License.
290N/A#
290N/A# When distributing Covered Code, include this CDDL HEADER in each
290N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
290N/A# If applicable, add the following below this CDDL HEADER, with the
290N/A# fields enclosed by brackets "[]" replaced with your own identifying
290N/A# information: Portions Copyright [yyyy] [name of copyright owner]
290N/A#
290N/A# CDDL HEADER END
290N/A#
3158N/A# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
395N/A# Use is subject to license terms.
290N/A#
3143N/A
883N/A# pkg.depotd - package repository daemon
454N/A
290N/Aimport BaseHTTPServer
448N/Aimport os
290N/Aimport re
290N/Aimport sha
290N/Aimport shutil
383N/Aimport time
290N/Aimport urllib
395N/A
290N/Aimport pkg.config as config
395N/Aimport pkg.content as content
849N/Aimport pkg.dependency as dependency
1516N/Aimport pkg.fmri as fmri
2508N/Aimport pkg.image as image
2826N/Aimport pkg.version as version
290N/A
2535N/Aimport pkg.server.catalog as catalog
2698N/Aimport pkg.server.package as package
290N/Aimport pkg.server.transaction as trans
290N/A
2535N/A# in_flight_trans needs to be rebuilt on restart
2561N/Ain_flight_trans = {}
290N/A
2508N/Adef catalog(scfg, request):
383N/A """The marshalled form of the catalog is
290N/A
290N/A pkg_name (release (branch (sequence ...) ...) ...)
2339N/A
2535N/A since we know that the server is only to report packages for which it
290N/A can offer a record.
290N/A """
2535N/A
2535N/A request.send_response(200)
290N/A request.send_header('Content-type:', 'text/plain')
290N/A request.end_headers()
2508N/A request.wfile.write('''GET URI %s ; headers %s''' % (request.path, request.headers))
2508N/A
290N/Adef trans_open(scfg, request):
1660N/A # XXX Authentication will be handled by virtue of possessing a signed
1660N/A # certificate (or a more elaborate system).
1660N/A t = trans.Transaction()
1660N/A
1660N/A ret = t.open(scfg, request)
1660N/A if ret == 200:
1660N/A in_flight_trans[t.get_basename()] = t
1660N/A
1660N/A request.send_response(200)
1660N/A request.send_header('Content-type', 'text/plain')
1660N/A request.send_header('Transaction-ID', t.get_basename())
1660N/A request.end_headers()
1660N/A elif ret == 400:
1660N/A request.send_response(400)
1660N/A else:
1660N/A request.send_response(500)
1660N/A
1660N/A
448N/Adef trans_close(scfg, request):
448N/A # Pull transaction ID from headers.
2828N/A m = re.match("^/close/(.*)", request.path)
2828N/A trans_id = m.group(1)
2828N/A
534N/A # XXX KeyError?
534N/A t = in_flight_trans[trans_id]
534N/A t.close(request)
534N/A del in_flight_trans[trans_id]
534N/A
534N/Adef trans_abandon(scfg, request):
534N/A # Pull transaction ID from headers.
290N/A m = re.match("^/abandon/(.*)", request.path)
290N/A trans_id = m.group(1)
954N/A
954N/A t = in_flight_trans[trans_id]
954N/A t.abandon(request)
954N/A del in_flight_trans[trans_id]
534N/A
1099N/Adef trans_add(scfg, request):
290N/A m = re.match("^/add/([^/]*)/(.*)", request.path)
3117N/A trans_id = m.group(1)
3117N/A type = m.group(2)
3203N/A
3117N/A t = in_flight_trans[trans_id]
290N/A t.add_content(request, type)
290N/A
290N/Aif "PKG_REPO" in os.environ:
661N/A scfg = config.SvrConfig(os.environ["PKG_REPO"])
2867N/Aelse:
290N/A scfg = config.SvrConfig("/var/pkg/repo")
2494N/A
2494N/Aclass pkgHandler(BaseHTTPServer.BaseHTTPRequestHandler):
2494N/A
2516N/A def do_GET(self):
2516N/A if re.match("^/catalog$", self.path):
2516N/A catalog(scfg, self)
2516N/A elif re.match("^/open/(.*)$", self.path):
2516N/A trans_open(scfg, self)
2516N/A elif re.match("^/close/(.*)$", self.path):
2516N/A trans_close(scfg, self)
290N/A elif re.match("^/abandon/(.*)$", self.path):
3185N/A trans_abandon(scfg, self)
2523N/A elif re.match("^/add/(.*)$", self.path):
3138N/A trans_add(scfg, self)
2390N/A elif re.match("^/$", self.path) or re.match("^/index.html", self.path):
1498N/A self.send_response(200)
1498N/A self.send_header('Content-type', 'text/html')
2867N/A self.end_headers()
2310N/A self.wfile.write("""<html><body><h1><code>pkg</code> server ok</h1>\n""")
2310N/A self.wfile.write("""</body></html>""")
2310N/A else:
2852N/A self.send_response(404)
2852N/A self.send_header('Content-type', 'text/plain')
2852N/A self.end_headers()
2852N/A self.wfile.write('''404 GET URI %s ; headers %s''' % (self.path, self.headers))
2535N/A
2867N/A
2867N/A def do_PUT(self):
2310N/A self.send_response(200)
290N/A self.send_header('Content-type:', 'text/plain')
1674N/A self.end_headers()
1674N/A self.wfile.write('''PUT URI %s ; headers %s''' % (self.path, self.headers))
2262N/A
1674N/A def do_POST(self):
395N/A if re.match("^/add/(.*)$", self.path):
430N/A trans_add(scfg, self)
395N/A else:
1544N/A self.send_response(404)
1968N/A
1557N/A def do_DELETE(self):
1903N/A self.send_response(200)
2046N/A self.send_header('Content-type:', 'text/plain')
2240N/A self.end_headers()
1506N/A self.wfile.write('''URI %s ; headers %s''' % (self.path, self.headers))
2928N/A
395N/Aif __name__ == "__main__":
395N/A scfg.init_dirs()
2026N/A server = BaseHTTPServer.HTTPServer(('', 10000), pkgHandler)
395N/A server.serve_forever()
395N/A