Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
ZODB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Nicolas Wavrant
ZODB
Commits
d3ed055a
Commit
d3ed055a
authored
Nov 19, 2002
by
Guido van Rossum
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial version of generic start.py rewrite. This is very fresh, but
seems to work.
parent
4d86e4e0
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
438 additions
and
0 deletions
+438
-0
src/ZEO/runsvr.py
src/ZEO/runsvr.py
+438
-0
No files found.
src/ZEO/runsvr.py
0 → 100644
View file @
d3ed055a
#! /usr/bin/env python
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Start the ZEO storage server.
Usage: %s [-a ADDRESS] [-d DIRECTORY]
[-f FILENAME] [-s STORAGE] [-u USER]
Options:
-a/--address ADDRESS -- server address of the form PORT, HOST:PORT, or PATH
(a PATH must contain at least one "/")
-f/--filename FILENAME -- filename for FileStorage
-s/--storage STORAGE -- storage specification of the form
NAME=MODULE[:ATTRIBUTE]
(multiple -s options are supported)
-u/--user USER -- username or uid of user to setuid()
-z/--directory DIRECTORY -- home directory (default $INSTANCE_HOME or `pwd`)
-a is required; either -f must be used or -s must be used.
"""
# The code here is designed to be reused by other, similar servers.
# For the forseeable future, it must work under Python 2.1 as well as
# 2.2 and above.
# XXX The option parsing infrastructure could be shared with zdaemon.py
import
os
import
sys
import
getopt
import
signal
import
socket
if
__name__
==
"__main__"
:
# Add the parent of the script directory to the module search path
from
os.path
import
dirname
,
abspath
,
normpath
sys
.
path
.
append
(
dirname
(
dirname
(
normpath
(
abspath
(
sys
.
argv
[
0
])))))
import
zLOG
class
Options
:
"""A class to parse and hold the command line options.
Options are represented by various attributes (zeoport etc.).
Positional arguments are represented by the args attribute.
This also has a public usage() method that can be used to report
errors related to the command line.
"""
args
=
[]
def
__init__
(
self
,
args
=
None
,
progname
=
None
,
doc
=
None
):
"""Constructor.
Optional arguments:
args -- the command line arguments, less the program name
(default is sys.argv[1:] at the time of call)
progname -- the program name (default sys.argv[0])
doc -- usage message (default, __main__.__doc__)
"""
if
args
is
None
:
args
=
sys
.
argv
[
1
:]
if
progname
is
None
:
progname
=
sys
.
argv
[
0
]
self
.
progname
=
progname
if
doc
is
None
:
import
__main__
doc
=
__main__
.
__doc__
if
doc
and
not
doc
.
endswith
(
"
\
n
"
):
doc
+=
"
\
n
"
self
.
doc
=
doc
try
:
self
.
opts
,
self
.
args
=
getopt
.
getopt
(
args
,
self
.
_short_options
,
self
.
_long_options
)
except
getopt
.
error
,
msg
:
self
.
usage
(
str
(
msg
))
for
opt
,
arg
in
self
.
opts
:
self
.
handle_option
(
opt
,
arg
)
self
.
check_options
()
# Default set of options. Subclasses should override.
_short_options
=
"h"
_long_options
=
[
"--help"
]
def
handle_option
(
self
,
opt
,
arg
):
"""Handle one option. Subclasses should override.
This sets the various instance variables overriding the defaults.
When -h is detected, print the module docstring to stdout and exit(0).
"""
if
opt
==
"-h"
or
opt
==
"--help"
:
self
.
help
()
def
check_options
(
self
):
"""Check options. Subclasses may override.
This can be used to ensure certain options are set, etc.
"""
pass
def
help
(
self
):
"""Print a long help message (self.doc) to stdout and exit(0).
Occurrences of "%s" in self.doc are replaced by self.progname.
"""
doc
=
self
.
doc
if
doc
.
find
(
"%s"
)
>
0
:
doc
=
doc
.
replace
(
"%s"
,
self
.
progname
)
print
doc
sys
.
exit
(
0
)
def
usage
(
self
,
msg
):
"""Print a brief error message to stderr and exit(2)."""
sys
.
stderr
.
write
(
"Error: %s
\
n
"
%
str
(
msg
))
sys
.
stderr
.
write
(
"For help, use %s -h
\
n
"
%
self
.
progname
)
sys
.
exit
(
2
)
class
ZEOOptions
(
Options
):
family
=
None
address
=
None
user
=
None
storages
=
None
filename
=
None
directory
=
None
_short_options
=
"a:d:f:hs:u:"
_long_options
=
[
"--address="
,
"--directory="
,
"--filename="
,
"--help"
,
"--storage="
,
"--user="
,
]
def
handle_option
(
self
,
opt
,
arg
):
# Alphabetical order please!
if
opt
in
(
"-a"
,
"--address"
):
if
"/"
in
arg
:
self
.
family
=
socket
.
AF_UNIX
self
.
address
=
arg
else
:
self
.
family
=
socket
.
AF_INET
if
":"
in
arg
:
host
,
port
=
arg
.
split
(
":"
,
1
)
else
:
host
=
""
port
=
arg
try
:
port
=
int
(
port
)
except
:
# int() can raise all sorts of errors
self
.
usage
(
"invalid port number: %r"
%
port
)
self
.
address
=
(
host
,
port
)
elif
opt
in
(
"-d"
,
"--directory"
):
self
.
directory
=
arg
elif
opt
in
(
"-f"
,
"--filename"
):
self
.
filename
=
arg
elif
opt
in
(
"-s"
,
"--storage"
):
if
self
.
storages
is
None
:
self
.
storages
=
{}
if
not
"="
in
arg
:
self
.
usage
(
"use -s/--storage storagename=module[:attribute]"
)
name
,
rest
=
arg
.
split
(
"="
,
1
)
if
":"
in
rest
:
module
,
attr
=
rest
.
split
(
":"
,
1
)
else
:
module
=
rest
attr
=
name
self
.
storages
[
name
]
=
module
,
attr
elif
opt
in
(
"-u"
,
"--user"
):
self
.
user
=
arg
else
:
# Pass it to the base class, for --help/-h
Options
.
handle_option
(
self
,
opt
,
arg
)
def
check_options
(
self
):
if
self
.
storages
and
self
.
filename
:
self
.
usage
(
"can't use both -s/--storage and -f/--filename"
)
if
not
self
.
storages
and
not
self
.
filename
:
self
.
usage
(
"need one of -s/--storage or -f/--filename"
)
if
self
.
family
is
None
:
self
.
usage
(
"need -a/--address [host:]port or unix path"
)
if
self
.
args
:
self
.
usage
(
"no positional arguments supported"
)
class
Server
:
OptionsClass
=
ZEOOptions
def
__init__
(
self
,
opts
=
None
):
if
opts
is
None
:
opts
=
self
.
OptionsClass
()
self
.
opts
=
opts
def
main
(
self
):
self
.
check_socket
()
self
.
clear_socket
()
self
.
set_uid
()
self
.
change_dir
()
self
.
open_storages
()
self
.
setup_signals
()
try
:
self
.
create_server
()
self
.
loop_forever
()
finally
:
self
.
clear_socket
()
def
check_socket
(
self
):
if
isinstance
(
self
.
opts
.
address
,
type
(
""
)):
s
=
socket
.
socket
(
socket
.
AF_UNIX
,
socket
.
SOCK_STREAM
)
else
:
s
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
try
:
s
.
connect
(
self
.
opts
.
address
)
except
socket
.
error
:
pass
else
:
s
.
close
()
self
.
opts
.
usage
(
"address %r still in use"
%
self
.
opts
.
address
)
def
clear_socket
(
self
):
if
isinstance
(
self
.
opts
.
address
,
type
(
""
)):
try
:
os
.
unlink
(
self
.
opts
.
address
)
except
os
.
error
:
pass
def
set_uid
(
self
):
if
self
.
opts
.
user
is
None
:
return
if
os
.
name
!=
"posix"
:
self
.
opts
.
usage
(
"-u/-user only supported on Unix"
)
if
os
.
geteuid
()
!=
0
:
self
.
opts
.
usage
(
"only root can use -u/--user"
)
# XXX Is it important not to die if the following fails?
import
pwd
try
:
uid
=
int
(
self
.
opts
.
user
)
except
:
# int() can raise all sorts of errors
try
:
pwrec
=
pwd
.
getpwnam
(
self
.
opts
.
user
)
except
KeyError
:
self
.
opts
.
usage
(
"username %r not found"
%
self
.
opts
.
user
)
uid
=
pwrec
[
2
]
else
:
try
:
pwrec
=
pwd
.
getpwuid
(
uid
)
except
KeyError
:
self
.
opts
.
usage
(
"uid %r not found"
%
self
.
opts
.
user
)
gid
=
pwrec
[
3
]
os
.
setgid
(
gid
)
os
.
setuid
(
uid
)
def
change_dir
(
self
):
if
self
.
opts
.
directory
:
try
:
os
.
chdir
(
self
.
opts
.
directory
)
except
os
.
error
:
self
.
opts
.
usage
(
"can't chdir into %r"
%
self
.
opts
.
directory
)
def
open_storages
(
self
):
if
self
.
opts
.
storages
:
self
.
load_storages
(
self
.
opts
.
storages
)
else
:
from
ZODB.FileStorage
import
FileStorage
info
(
"opening storage '1': %r"
%
self
.
opts
.
filename
)
storage
=
FileStorage
(
self
.
opts
.
filename
)
self
.
storages
=
{
"1"
:
storage
}
def
load_storages
(
self
,
storages
):
self
.
storages
=
{}
for
name
,
(
module
,
attr
)
in
storages
.
items
():
info
(
"opening storage %r (%r:%r)"
%
(
name
,
module
,
attr
))
self
.
storages
[
name
]
=
self
.
get_storage
(
module
,
attr
)
_storage_cache
=
{}
def
get_storage
(
self
,
module
,
attr
):
# XXX This may fail with ImportError or AttributeError
path
=
sys
.
path
dir
,
module
=
os
.
path
.
split
(
module
)
if
module
.
lower
().
endswith
(
'.py'
):
module
=
module
[:
-
3
]
im
=
self
.
_storage_cache
.
get
((
dir
,
module
))
if
im
is
None
:
if
dir
:
path
=
[
dir
]
+
path
import
imp
im
=
imp
.
find_module
(
module
,
path
)
im
=
imp
.
load_module
(
module
,
*
im
)
self
.
_storage_cache
[(
dir
,
module
)]
=
im
return
getattr
(
im
,
attr
)
def
setup_signals
(
self
):
"""Set up signal handlers.
The signal handler for SIGFOO is a method handle_sigfoo().
If no handler method is defined for a signal, the signal
action is not changed from its initial value. The handler
method is called without additional arguments.
"""
if
os
.
name
!=
"posix"
:
return
if
hasattr
(
signal
,
'SIGXFSZ'
):
signal
.
signal
(
signal
.
SIGXFSZ
,
signal
.
SIG_IGN
)
# Special case
init_signames
()
for
sig
,
name
in
signames
.
items
():
method
=
getattr
(
self
,
"handle_"
+
name
.
lower
(),
None
)
if
method
is
not
None
:
def
wrapper
(
sig_dummy
,
frame_dummy
,
method
=
method
):
method
()
signal
.
signal
(
sig
,
wrapper
)
def
create_server
(
self
):
from
ZEO.StorageServer
import
StorageServer
self
.
server
=
StorageServer
(
self
.
opts
.
address
,
self
.
storages
)
def
loop_forever
(
self
):
import
asyncore
asyncore
.
loop
()
def
handle_sigterm
(
self
):
info
(
"terminated by SIGTERM"
)
self
.
close_storages
()
sys
.
exit
(
0
)
def
handle_sigint
(
self
):
info
(
"terminated by SIGINT"
)
self
.
close_storages
()
sys
.
exit
(
0
)
def
handle_sigusr2
(
self
):
# This requires a modern zLOG (from Zope 2.6 or later); older
# zLOG packages don't have the initialize() method
info
(
"reinitializing zLOG"
)
# XXX Shouldn't this be below with _log()?
import
zLOG
zLOG
.
initialize
()
def
close_storages
(
self
):
for
name
,
storage
in
self
.
storages
.
items
():
info
(
"closing storage %r"
%
name
)
try
:
storage
.
close
()
except
:
# Keep going
exception
(
"failed to close storage %r"
%
name
)
# Signal names
signames
=
None
def
signame
(
sig
):
"""Return a symbolic name for a signal.
Return "signal NNN" if there is no corresponding SIG name in the
signal module.
"""
if
signames
is
None
:
init_signames
()
return
signames
.
get
(
sig
)
or
"signal %d"
%
sig
def
init_signames
():
global
signames
signames
=
{}
for
name
,
sig
in
signal
.
__dict__
.
items
():
k_startswith
=
getattr
(
name
,
"startswith"
,
None
)
if
k_startswith
is
None
:
continue
if
k_startswith
(
"SIG"
)
and
not
k_startswith
(
"SIG_"
):
signames
[
sig
]
=
name
# Log messages with various severities.
# This uses zLOG, but the API is a simplified version of PEP 282
def
critical
(
msg
):
"""Log a critical message."""
_log
(
msg
,
zLOG
.
PANIC
)
def
error
(
msg
):
"""Log an error message."""
_log
(
msg
,
zLOG
.
ERROR
)
def
exception
(
msg
):
"""Log an exception (an error message with a traceback attached)."""
_log
(
msg
,
zLOG
.
ERROR
,
error
=
sys
.
exc_info
())
def
warn
(
msg
):
"""Log a warning message."""
_log
(
msg
,
zLOG
.
PROBLEM
)
def
info
(
msg
):
"""Log an informational message."""
_log
(
msg
,
zLOG
.
INFO
)
def
debug
(
msg
):
"""Log a debugging message."""
_log
(
msg
,
zLOG
.
DEBUG
)
def
_log
(
msg
,
severity
=
zLOG
.
INFO
,
error
=
None
):
"""Internal: generic logging function."""
zLOG
.
LOG
(
"RUNSVR"
,
severity
,
msg
,
""
,
error
)
# Main program
def
main
(
args
=
None
):
opts
=
Server
.
OptionsClass
(
args
)
s
=
Server
(
opts
)
s
.
main
()
if
__name__
==
"__main__"
:
main
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment