111
112 class LogSink(object):
113 """This is a dummy object that we can use to discard log entries
114 without relying on non-portable interfaces such as /dev/null."""
115
116 def write(self, *args, **kwargs):
117 """Discard the bits."""
118 pass
119
120 def flush(self, *args, **kwargs):
121 """Discard the bits."""
122 pass
123
124 def usage(text):
125 if text:
126 emsg(text)
127
128 print """\
129 Usage: /usr/lib/pkg.depotd [-d repo_dir] [-p port] [-s threads]
130 [-t socket_timeout] [--cfg-file] [--content-root] [--debug]
131 [--log-access dest] [--log-errors dest] [--mirror] [--proxy-base url]
132 [--readonly] [--rebuild] [--ssl-cert-file] [--ssl-dialog]
133 [--ssl-key-file] [--writable-root dir]
134
135 --cfg-file The pathname of the file from which to read and to
136 write configuration information.
137 --content-root The file system path to the directory containing the
138 the static and other web content used by the depot's
139 browser user interface. The default value is
140 '/usr/share/lib/pkg'.
141 --debug The name of a debug feature to enable; or a whitespace
142 or comma separated list of features to enable. Possible
143 values are: headers.
144 --log-access The destination for any access related information
145 logged by the depot process. Possible values are:
146 stderr, stdout, none, or an absolute pathname. The
147 default value is stdout if stdout is a tty; otherwise
148 the default value is none.
149 --log-errors The destination for any errors or other information
150 logged by the depot process. Possible values are:
151 stderr, stdout, none, or an absolute pathname. The
152 default value is stderr.
153 --mirror Package mirror mode; publishing and metadata operations
154 disallowed. Cannot be used with --readonly or
155 --rebuild.
156 --proxy-base The url to use as the base for generating internal
157 redirects and content.
158 --readonly Read-only operation; modifying operations disallowed.
159 Cannot be used with --mirror or --rebuild.
160 --rebuild Re-build the catalog from pkgs in depot. Cannot be
161 used with --mirror or --readonly.
162 --ssl-cert-file The absolute pathname to a PEM-encoded Certificate file.
163 This option must be used with --ssl-key-file. Usage of
164 this option will cause the depot to only respond to SSL
165 requests on the provided port.
166 --ssl-dialog Specifies what method should be used to obtain the
167 passphrase needed to decrypt the file specified by
168 --ssl-key-file. Supported values are: builtin,
169 exec:/path/to/program, or smf:fmri. The default value
170 is builtin.
171 --ssl-key-file The absolute pathname to a PEM-encoded Private Key file.
172 This option must be used with --ssl-cert-file. Usage of
173 this option will cause the depot to only respond to SSL
174 requests on the provided port.
175 --writable-root The path to a directory to which the program has write
185 def __init__(self, *args):
186 Exception.__init__(self, *args)
187
188 if __name__ == "__main__":
189
190 setlocale(locale.LC_ALL, "")
191 gettext.install("pkg", "/usr/share/locale")
192
193 debug_features = {
194 "headers": False,
195 }
196 port = PORT_DEFAULT
197 port_provided = False
198 threads = THREADS_DEFAULT
199 socket_timeout = SOCKET_TIMEOUT_DEFAULT
200 readonly = READONLY_DEFAULT
201 rebuild = REBUILD_DEFAULT
202 reindex = REINDEX_DEFAULT
203 proxy_base = None
204 mirror = MIRROR_DEFAULT
205 repo_config_file = None
206 ssl_cert_file = None
207 ssl_key_file = None
208 ssl_dialog = "builtin"
209 writable_root = None
210
211 if "PKG_REPO" in os.environ:
212 repo_path = os.environ["PKG_REPO"]
213 else:
214 repo_path = REPO_PATH_DEFAULT
215
216 try:
217 content_root = os.environ["PKG_DEPOT_CONTENT"]
218 except KeyError:
219 try:
220 content_root = os.path.join(os.environ['PKG_HOME'],
221 'share/lib/pkg')
222 except KeyError:
223 content_root = CONTENT_PATH_DEFAULT
224
225 # By default, if the destination for a particular log type is not
226 # specified, this is where we will send the output.
227 log_routes = {
228 "access": "none",
229 "errors": "stderr"
230 }
231 log_opts = ["--log-%s" % log_type for log_type in log_routes]
232
233 # If stdout is a tty, then send access output there by default instead
234 # of discarding it.
235 if os.isatty(sys.stdout.fileno()):
236 log_routes["access"] = "stdout"
237
238 opt = None
239 try:
240 long_opts = ["cfg-file=", "content-root=", "debug=", "mirror",
241 "proxy-base=", "readonly", "rebuild", "refresh-index",
242 "ssl-cert-file=", "ssl-dialog=", "ssl-key-file=",
243 "writable-root="]
244 for opt in log_opts:
245 long_opts.append("%s=" % opt.lstrip('--'))
246 opts, pargs = getopt.getopt(sys.argv[1:], "d:np:s:t:",
247 long_opts)
248 for opt, arg in opts:
249 if opt == "-n":
250 sys.exit(0)
251 elif opt == "-d":
252 repo_path = arg
253 elif opt == "-p":
254 port = int(arg)
255 port_provided = True
256 elif opt == "-s":
257 threads = int(arg)
258 if threads < THREADS_MIN:
259 raise OptionError, \
260 "minimum value is %d" % THREADS_MIN
261 if threads > THREADS_MAX:
262 raise OptionError, \
263 "maximum value is %d" % THREADS_MAX
279 # "," or any whitespace character as separators.
280 if "," in arg:
281 features = arg.split(",")
282 else:
283 features = arg.split()
284
285 for f in features:
286 if f not in debug_features:
287 raise OptionError, \
288 "Invalid debug feature: " \
289 "%s." % f
290 debug_features[f] = True
291 elif opt in log_opts:
292 if arg is None or arg == "":
293 raise OptionError, \
294 "You must specify a log " \
295 "destination."
296 log_routes[opt.lstrip("--log-")] = arg
297 elif opt == "--mirror":
298 mirror = True
299 elif opt == "--proxy-base":
300 # Attempt to decompose the url provided into
301 # its base parts. This is done so we can
302 # remove any scheme information since we
303 # don't need it.
304 scheme, netloc, path, params, query, \
305 fragment = urlparse.urlparse(arg,
306 "http", allow_fragments=0)
307
308 if not netloc:
309 raise OptionError, "Unable to " \
310 "determine the hostname from " \
311 "the provided URL; please use a " \
312 "fully qualified URL."
313
314 scheme = scheme.lower()
315 if scheme not in ("http", "https"):
316 raise OptionError, "Invalid URL; http " \
317 "and https are the only supported " \
318 "schemes."
426 "must both be provided when using either option.")
427 elif ssl_cert_file and ssl_key_file and not port_provided:
428 # If they didn't already specify a particular port, use the
429 # default SSL port instead.
430 port = SSL_PORT_DEFAULT
431
432 # If the program is going to reindex, the port is irrelevant since
433 # the program will not bind to a port.
434 if not reindex:
435 available, msg = port_available(None, port)
436 if not available:
437 print "pkg.depotd: unable to bind to the specified " \
438 "port: %d. Reason: %s" % (port, msg)
439 sys.exit(1)
440 else:
441 # Not applicable for reindexing operations.
442 content_root = None
443
444 fork_allowed = not reindex
445
446 scfg = config.SvrConfig(repo_path, content_root, AUTH_DEFAULT,
447 auto_create=not readonly, fork_allowed=fork_allowed,
448 writable_root=writable_root)
449
450 if readonly:
451 scfg.set_read_only()
452
453 if mirror:
454 scfg.set_mirror()
455
456 try:
457 scfg.init_dirs()
458 except (errors.SvrConfigError, EnvironmentError), _e:
459 print "pkg.depotd: an error occurred while trying to " \
460 "initialize the depot repository directory " \
461 "structures:\n%s" % _e
462 sys.exit(1)
463
464 key_data = None
465 if not reindex and ssl_cert_file and ssl_key_file and \
466 ssl_dialog != "builtin":
467 cmdline = None
468 def get_ssl_passphrase(*ignored):
469 p = None
470 try:
471 p = subprocess.Popen(cmdline, shell=True,
472 stdout=subprocess.PIPE,
473 stderr=None)
474 p.wait()
475 except Exception, __e:
611 # http://cherrypy.org/wiki/BuiltinTools#tools.proxy
612 proxy_conf = {
613 "tools.proxy.on": True,
614 "tools.proxy.local": "",
615 "tools.proxy.base": proxy_base
616 }
617
618 # Now merge or add our proxy configuration information into the
619 # existing configuration.
620 for entry in proxy_conf:
621 conf["/"][entry] = proxy_conf[entry]
622
623 scfg.acquire_in_flight()
624 try:
625 scfg.acquire_catalog(rebuild=rebuild, verbose=True)
626 except (catalog.CatalogPermissionsException, errors.SvrConfigError), _e:
627 emsg("pkg.depotd: %s" % _e)
628 sys.exit(1)
629
630 try:
631 root = cherrypy.Application(depot.DepotHTTP(scfg,
632 repo_config_file))
633 except rc.InvalidAttributeValueError, _e:
634 emsg("pkg.depotd: repository.conf error: %s" % _e)
635 sys.exit(1)
636
637 try:
638 cherrypy.quickstart(root, config=conf)
639 except Exception, _e:
640 emsg("pkg.depotd: unknown error starting depot server, " \
641 "illegal option value specified?")
642 emsg(_e)
643 sys.exit(1)
|
111
112 class LogSink(object):
113 """This is a dummy object that we can use to discard log entries
114 without relying on non-portable interfaces such as /dev/null."""
115
116 def write(self, *args, **kwargs):
117 """Discard the bits."""
118 pass
119
120 def flush(self, *args, **kwargs):
121 """Discard the bits."""
122 pass
123
124 def usage(text):
125 if text:
126 emsg(text)
127
128 print """\
129 Usage: /usr/lib/pkg.depotd [-d repo_dir] [-p port] [-s threads]
130 [-t socket_timeout] [--cfg-file] [--content-root] [--debug]
131 [--log-access dest] [--log-errors dest] [--mirror] [--nasty]
132 [--proxy-base url] [--readonly] [--rebuild] [--ssl-cert-file]
133 [--ssl-dialog] [--ssl-key-file] [--writable-root dir]
134
135 --cfg-file The pathname of the file from which to read and to
136 write configuration information.
137 --content-root The file system path to the directory containing the
138 the static and other web content used by the depot's
139 browser user interface. The default value is
140 '/usr/share/lib/pkg'.
141 --debug The name of a debug feature to enable; or a whitespace
142 or comma separated list of features to enable. Possible
143 values are: headers.
144 --log-access The destination for any access related information
145 logged by the depot process. Possible values are:
146 stderr, stdout, none, or an absolute pathname. The
147 default value is stdout if stdout is a tty; otherwise
148 the default value is none.
149 --log-errors The destination for any errors or other information
150 logged by the depot process. Possible values are:
151 stderr, stdout, none, or an absolute pathname. The
152 default value is stderr.
153 --mirror Package mirror mode; publishing and metadata operations
154 disallowed. Cannot be used with --readonly or
155 --rebuild.
156 --nasty Instruct the server to misbehave. At random intervals
157 it will time-out, send bad responses, hang up on
158 clients, and generally be hostile. The option
159 takes a value (1 to 100) for how nasty the server
160 should be.
161 --proxy-base The url to use as the base for generating internal
162 redirects and content.
163 --readonly Read-only operation; modifying operations disallowed.
164 Cannot be used with --mirror or --rebuild.
165 --rebuild Re-build the catalog from pkgs in depot. Cannot be
166 used with --mirror or --readonly.
167 --ssl-cert-file The absolute pathname to a PEM-encoded Certificate file.
168 This option must be used with --ssl-key-file. Usage of
169 this option will cause the depot to only respond to SSL
170 requests on the provided port.
171 --ssl-dialog Specifies what method should be used to obtain the
172 passphrase needed to decrypt the file specified by
173 --ssl-key-file. Supported values are: builtin,
174 exec:/path/to/program, or smf:fmri. The default value
175 is builtin.
176 --ssl-key-file The absolute pathname to a PEM-encoded Private Key file.
177 This option must be used with --ssl-cert-file. Usage of
178 this option will cause the depot to only respond to SSL
179 requests on the provided port.
180 --writable-root The path to a directory to which the program has write
190 def __init__(self, *args):
191 Exception.__init__(self, *args)
192
193 if __name__ == "__main__":
194
195 setlocale(locale.LC_ALL, "")
196 gettext.install("pkg", "/usr/share/locale")
197
198 debug_features = {
199 "headers": False,
200 }
201 port = PORT_DEFAULT
202 port_provided = False
203 threads = THREADS_DEFAULT
204 socket_timeout = SOCKET_TIMEOUT_DEFAULT
205 readonly = READONLY_DEFAULT
206 rebuild = REBUILD_DEFAULT
207 reindex = REINDEX_DEFAULT
208 proxy_base = None
209 mirror = MIRROR_DEFAULT
210 nasty = False
211 nasty_value = 0
212 repo_config_file = None
213 ssl_cert_file = None
214 ssl_key_file = None
215 ssl_dialog = "builtin"
216 writable_root = None
217
218 if "PKG_REPO" in os.environ:
219 repo_path = os.environ["PKG_REPO"]
220 else:
221 repo_path = REPO_PATH_DEFAULT
222
223 try:
224 content_root = os.environ["PKG_DEPOT_CONTENT"]
225 except KeyError:
226 try:
227 content_root = os.path.join(os.environ['PKG_HOME'],
228 'share/lib/pkg')
229 except KeyError:
230 content_root = CONTENT_PATH_DEFAULT
231
232 # By default, if the destination for a particular log type is not
233 # specified, this is where we will send the output.
234 log_routes = {
235 "access": "none",
236 "errors": "stderr"
237 }
238 log_opts = ["--log-%s" % log_type for log_type in log_routes]
239
240 # If stdout is a tty, then send access output there by default instead
241 # of discarding it.
242 if os.isatty(sys.stdout.fileno()):
243 log_routes["access"] = "stdout"
244
245 opt = None
246 try:
247 long_opts = ["cfg-file=", "content-root=", "debug=", "mirror",
248 "nasty=", "proxy-base=", "readonly", "rebuild",
249 "refresh-index", "ssl-cert-file=", "ssl-dialog=",
250 "ssl-key-file=", "writable-root="]
251 for opt in log_opts:
252 long_opts.append("%s=" % opt.lstrip('--'))
253 opts, pargs = getopt.getopt(sys.argv[1:], "d:np:s:t:",
254 long_opts)
255 for opt, arg in opts:
256 if opt == "-n":
257 sys.exit(0)
258 elif opt == "-d":
259 repo_path = arg
260 elif opt == "-p":
261 port = int(arg)
262 port_provided = True
263 elif opt == "-s":
264 threads = int(arg)
265 if threads < THREADS_MIN:
266 raise OptionError, \
267 "minimum value is %d" % THREADS_MIN
268 if threads > THREADS_MAX:
269 raise OptionError, \
270 "maximum value is %d" % THREADS_MAX
286 # "," or any whitespace character as separators.
287 if "," in arg:
288 features = arg.split(",")
289 else:
290 features = arg.split()
291
292 for f in features:
293 if f not in debug_features:
294 raise OptionError, \
295 "Invalid debug feature: " \
296 "%s." % f
297 debug_features[f] = True
298 elif opt in log_opts:
299 if arg is None or arg == "":
300 raise OptionError, \
301 "You must specify a log " \
302 "destination."
303 log_routes[opt.lstrip("--log-")] = arg
304 elif opt == "--mirror":
305 mirror = True
306 elif opt == "--nasty":
307 value_err = None
308 try:
309 nasty_value = int(arg)
310 except ValueError, e:
311 value_err = e
312
313 if value_err or (nasty_value > 100 or
314 nasty_value < 1):
315 raise OptionError, "Invalid value " \
316 "for nasty option.\n Please " \
317 "choose a value between 1 and 100."
318 nasty = True
319 elif opt == "--proxy-base":
320 # Attempt to decompose the url provided into
321 # its base parts. This is done so we can
322 # remove any scheme information since we
323 # don't need it.
324 scheme, netloc, path, params, query, \
325 fragment = urlparse.urlparse(arg,
326 "http", allow_fragments=0)
327
328 if not netloc:
329 raise OptionError, "Unable to " \
330 "determine the hostname from " \
331 "the provided URL; please use a " \
332 "fully qualified URL."
333
334 scheme = scheme.lower()
335 if scheme not in ("http", "https"):
336 raise OptionError, "Invalid URL; http " \
337 "and https are the only supported " \
338 "schemes."
446 "must both be provided when using either option.")
447 elif ssl_cert_file and ssl_key_file and not port_provided:
448 # If they didn't already specify a particular port, use the
449 # default SSL port instead.
450 port = SSL_PORT_DEFAULT
451
452 # If the program is going to reindex, the port is irrelevant since
453 # the program will not bind to a port.
454 if not reindex:
455 available, msg = port_available(None, port)
456 if not available:
457 print "pkg.depotd: unable to bind to the specified " \
458 "port: %d. Reason: %s" % (port, msg)
459 sys.exit(1)
460 else:
461 # Not applicable for reindexing operations.
462 content_root = None
463
464 fork_allowed = not reindex
465
466 if nasty:
467 scfg = config.NastySvrConfig(repo_path, content_root,
468 AUTH_DEFAULT, auto_create=not readonly,
469 fork_allowed=fork_allowed, writable_root=writable_root)
470 scfg.set_nasty(nasty_value)
471 else:
472 scfg = config.SvrConfig(repo_path, content_root, AUTH_DEFAULT,
473 auto_create=not readonly, fork_allowed=fork_allowed,
474 writable_root=writable_root)
475
476 if readonly:
477 scfg.set_read_only()
478
479 if mirror:
480 scfg.set_mirror()
481
482
483 try:
484 scfg.init_dirs()
485 except (errors.SvrConfigError, EnvironmentError), _e:
486 print "pkg.depotd: an error occurred while trying to " \
487 "initialize the depot repository directory " \
488 "structures:\n%s" % _e
489 sys.exit(1)
490
491 key_data = None
492 if not reindex and ssl_cert_file and ssl_key_file and \
493 ssl_dialog != "builtin":
494 cmdline = None
495 def get_ssl_passphrase(*ignored):
496 p = None
497 try:
498 p = subprocess.Popen(cmdline, shell=True,
499 stdout=subprocess.PIPE,
500 stderr=None)
501 p.wait()
502 except Exception, __e:
638 # http://cherrypy.org/wiki/BuiltinTools#tools.proxy
639 proxy_conf = {
640 "tools.proxy.on": True,
641 "tools.proxy.local": "",
642 "tools.proxy.base": proxy_base
643 }
644
645 # Now merge or add our proxy configuration information into the
646 # existing configuration.
647 for entry in proxy_conf:
648 conf["/"][entry] = proxy_conf[entry]
649
650 scfg.acquire_in_flight()
651 try:
652 scfg.acquire_catalog(rebuild=rebuild, verbose=True)
653 except (catalog.CatalogPermissionsException, errors.SvrConfigError), _e:
654 emsg("pkg.depotd: %s" % _e)
655 sys.exit(1)
656
657 try:
658 if nasty:
659 root = cherrypy.Application(depot.NastyDepotHTTP(scfg,
660 repo_config_file))
661 else:
662 root = cherrypy.Application(depot.DepotHTTP(scfg,
663 repo_config_file))
664 except rc.InvalidAttributeValueError, _e:
665 emsg("pkg.depotd: repository.conf error: %s" % _e)
666 sys.exit(1)
667
668 try:
669 cherrypy.quickstart(root, config=conf)
670 except Exception, _e:
671 emsg("pkg.depotd: unknown error starting depot server, " \
672 "illegal option value specified?")
673 emsg(_e)
674 sys.exit(1)
|