depot.py revision 22
1516N/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#
2339N/A# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
395N/A# Use is subject to license terms.
290N/A#
883N/A
454N/A# pkg.depotd - package repository daemon
290N/A
448N/Aimport BaseHTTPServer
290N/Aimport os
290N/Aimport re
290N/Aimport sha
383N/Aimport shutil
290N/Aimport time
395N/Aimport urllib
290N/A
395N/Aimport pkg.catalog as catalog
849N/Aimport pkg.config as config
1516N/Aimport pkg.content as content
2508N/Aimport pkg.dependency as dependency
290N/Aimport pkg.fmri as fmri
849N/Aimport pkg.image as image
290N/Aimport pkg.package as package
290N/Aimport pkg.transaction as trans
290N/Aimport pkg.version as version
290N/A
2508N/A# in_flight_trans needs to be rebuilt on restart
383N/Ain_flight_trans = {}
290N/A
290N/Adef catalog(scfg, request):
2339N/A """The marshalled form of the catalog is
290N/A
290N/A pkg_name (release (branch (sequence ...) ...) ...)
290N/A
290N/A since we know that the server is only to report packages for which it
290N/A can offer a record.
2508N/A """
2508N/A
290N/A request.send_response(200)
1660N/A request.send_header('Content-type:', 'text/plain')
1660N/A request.end_headers()
1660N/A request.wfile.write('''GET URI %s ; headers %s''' % (request.path, request.headers))
1660N/A
1660N/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:
448N/A request.send_response(400)
448N/A else:
534N/A request.send_response(500)
534N/A
534N/A
534N/Adef trans_close(scfg, request):
534N/A # Pull transaction ID from headers.
534N/A m = re.match("^/close/(.*)", request.path)
534N/A trans_id = m.group(1)
290N/A
290N/A # XXX KeyError?
954N/A t = in_flight_trans[trans_id]
954N/A t.close(request)
954N/A del in_flight_trans[trans_id]
954N/A
534N/Adef trans_abandon(scfg, request):
1099N/A # Pull transaction ID from headers.
290N/A m = re.match("^/abandon/(.*)", request.path)
1516N/A trans_id = m.group(1)
290N/A
290N/A t = in_flight_trans[trans_id]
290N/A t.abandon(request)
661N/A del in_flight_trans[trans_id]
290N/A
2494N/Adef trans_add(scfg, request):
2494N/A m = re.match("^/add/([^/]*)/(.*)", request.path)
2494N/A trans_id = m.group(1)
2516N/A type = m.group(2)
2516N/A
2516N/A t = in_flight_trans[trans_id]
2516N/A t.add_content(request, type)
2516N/A
2516N/Aif "PKG_REPO" in os.environ:
2516N/A scfg = config.SvrConfig(os.environ["PKG_REPO"])
290N/Aelse:
2390N/A scfg = config.SvrConfig("/var/pkg/repo")
1498N/A
1498N/Aclass pkgHandler(BaseHTTPServer.BaseHTTPRequestHandler):
2310N/A
2310N/A def do_GET(self):
2310N/A if re.match("^/catalog$", self.path):
2310N/A catalog(scfg, self)
290N/A elif re.match("^/open/(.*)$", self.path):
1674N/A trans_open(scfg, self)
1674N/A elif re.match("^/close/(.*)$", self.path):
2262N/A trans_close(scfg, self)
1674N/A elif re.match("^/abandon/(.*)$", self.path):
395N/A trans_abandon(scfg, self)
430N/A elif re.match("^/add/(.*)$", self.path):
395N/A trans_add(scfg, self)
1544N/A elif re.match("^/$", self.path) or re.match("^/index.html", self.path):
1968N/A self.send_response(200)
1557N/A self.send_header('Content-type', 'text/html')
1903N/A self.end_headers()
2046N/A self.wfile.write("""<html><body><h1><code>pkg</code> server ok</h1>\n""")
2240N/A self.wfile.write("""</body></html>""")
1506N/A else:
395N/A self.send_response(404)
395N/A self.send_header('Content-type', 'text/plain')
2026N/A self.end_headers()
424N/A self.wfile.write('''404 GET URI %s ; headers %s''' % (self.path, self.headers))
1024N/A
395N/A
395N/A def do_PUT(self):
395N/A self.send_response(200)
2078N/A self.send_header('Content-type:', 'text/plain')
578N/A self.end_headers()
1172N/A self.wfile.write('''PUT URI %s ; headers %s''' % (self.path, self.headers))
2310N/A
395N/A def do_POST(self):
661N/A if re.match("^/add/(.*)$", self.path):
1099N/A trans_add(scfg, self)
1902N/A else:
2310N/A self.send_response(404)
661N/A
395N/A def do_DELETE(self):
849N/A self.send_response(200)
290N/A self.send_header('Content-type:', 'text/plain')
395N/A self.end_headers()
395N/A self.wfile.write('''URI %s ; headers %s''' % (self.path, self.headers))
1968N/A
395N/Aif __name__ == "__main__":
395N/A scfg.init_dirs()
395N/A server = BaseHTTPServer.HTTPServer(('', 10000), pkgHandler)
395N/A server.serve_forever()
395N/A