|
5. Pyro Name Server
Brief: it's just like a filesystem with directories and files, and path separators.
Verbose: Pyro's object naming is hierarchical. Let's call the full set of names the namespace. A namespace has a single root that contains all other names. A name in the namespace is the name of a group or an object. A group can contain other groups, and objects. The root is a group.
Object names can be absolute or relative. Relative object names are searched in the default group (which has a special name, set by PYRO_NS_DEFAULTGROUP ). Absolute names are always searched from the root. Absolute object names start with a special character that signifies the root; the colon (': '). Relative object names don't have this character at the start.
Object names can be simple or compound. Compound object names consist of multiple parts separated by a special group separator character: the dot ('. '). Compound names are used to search within the namespace hierarchy. Each component of the name is the name of a group. The last name component can be the name of a group or an object (usually the latter).
Let's finish with a few examples to clarify all this. Note that by name alone you cannot distinguish a group name or an object name.
:
| The namespace root group
| :TestObj
| The TestObj name in the root (most likely an object name)
| :Test.simple.object1
| The object1 name in the simple group in the Test group in the root.
| Test.simple.object1
| The object1 name in the simple group in the Test group in the default group (which is ":Default" if not configured otherwise. This is the Default group in the root).
| object1
| The object1 name in the default group.
|
There are two kinds of Name Servers available at the moment:
- Regular, non-persistent (
Pyro.naming.NameServer )
- Persistent (
Pyro.naming.PersistentNameServer )
The non-persistent NS stores its naming database only in memory. It is really fast because
of that, but when it stops or crashes, the naming database is lost. All objects that were
registered in the NS have to be re-registered.
The persistent NS stores its naming database on disk. Currently this is implemented the easy
way; there is a direct mapping between the group names and directories on disk, and between
object names + URI's and files in these directories on disk. The database by default is
stored in a "Pyro_NS_database" directory that is created in the directory configured
by PYRO_STORAGE . There is a special option for the script that specifies
another location, if needed. See below.
Usually you don't access the NameServer or PersistentNameServer classes
directly: there are scripts to start the right name server.
Connecting objects to the Pyro Daemon with persistent naming
Usually you'll use the connect method of the daemon to connect your object
instances to the daemon on the server. The daemon will register your object with the
name server too, if you supplied a NS to the daemon and your object isn't transient (it has a name).
But, when using the persistent name server, there is a complication here: if you didn't explicitly remove your object from the NS, the entry will still be there the next time. Your connect
attempt will then fail because your object cannot be registered again in the NS.
The solution is to use the connectPersistent method of the Pyro daemon.
Except for the method name, you call it exactly like the regular connect method.
It tries to find your object in the NS. If it's there already, the previous URI is used for your object
(that also means that the object's GUID is replaced by the previous GUID that was found in the
NS). If it isn't there, the regular connect call takes over.
Of course you could always play safe and explicitly unregister any possible previous occurrences from the NS before you connect new instances. This is what all examples do by the way, so you can
safely run an example again and again.
For your information, the code that starts the Persistent Name Server uses connectPersistent to connect the name server object to the daemon. Why? because the name server itself
is also registered in the NS database, and it is necessary that when the NS restarts, it
uses the URI of the previous instance if found in the persistent database.
The Name Server supports security plugins, to facilitate access control to the Name Server.
When starting the NS, you can supply an option that tells the NS to load that
specific Python module and use the security plugins that you defined in there.
For more information, see the Security chapter, topic "Name Server security plugins".
There are a few commands (actually scripts) supplied in the bin directory that will start a Pyro Name Server for you:
ns (Name Server)
- - Arguments: [-h] [-k] [-m] [-n hostname] [-p port] [-b port] [-i identification] [-d [databasefile]] [-s securitymodule]
- Starts the Pyro Name Server. The '-h' argument prints some help, '-k' makes it immune to shutdown requests (a crude form of security against malicious shutdown requests), '-m' allows multiple
Name Servers to be started in the same network segment (default=not allowed),
'-n hostname' selects the hostname the server should bind on (useful on systems with multiple network adapters/hostnames),
'-p port' specifies the Name Server port number, '-b port' specifies the broadcast port number.
With '-i identification' you can supply the authentication passphrase that will be required to connect to this server. When it contains spaces, use quotes around it.
'-d' starts the persistent server. You can provide an optional filename to the last option to specify the database file.
The '-s' option specifies the Python module for security plugins (make sure it is in your PYTHONPATH).
rns (Restarting Name Server)
- This is very much the same as the
ns command but the script will restart the
name server if it quits or crashes. Do not confuse this with the -d argument,
which will start a Name Server that has its database persistent on disk. Of course it is
very useful to combine the rns with the -d switch!!!
ns.bat, rns.bat
- The Windows scripts for the above.
Using the nsc command (explained in the Usage chapter) you can control a Name
Server that is already running.
Consider setting PYRO_CHECKSUM to 1 before starting the NS. It will communicate more reliably
and the overhead is very small.
If you want to start the NS from within your own program, you can ofcourse start it by executing
the start script mentioned above. You could also use the NameServerStarter class
from the Pyro.naming module
to start it directly (this is what the script eventually does). Be sure to start it
in a separate process or thread because it will run in its own endless loop.
Pyro's NS is actually two servers: the normal Pyro server but when using
TCP/IP sockets, also a broadcast listener.
The latter helps clients find the location of the Name Server by answering
to broadcast packet requests. To hide that broadcast lookup mechanism
from you, and to make the lookup very easy, we have the NameServer Locator,
defined in the Pyro.naming package.
This object gets a Pyro proxy for the NS for you.
Because this is the recommended (and easiest way) to gain access to the Name Server,
you're not interested in the internal name Pyro uses for the Name Server.
But for consistency, it is defined, and the Name Server object itself is known
in the Name Server's namespace under the name available in Pyro.constants.NAMESERVER_NAME .
There are essentially three ways to get a reference to the Name Server:
- Use the
NameServerLocator 's broadcast mechanism. This only works if your network supports broadcasting and the NS is reachable by a broadcast request.
locator = Pyro.naming.NameServerLocator()
ns = locator.getNS()
If your network doesn't allow broadcasts, or the broadcast can't reach the NS, this mechanism doesn't work.
There is a simple workaround: just set the PYRO_NS_HOSTNAME config option to the hostname
on which your NS can be found. This disables the broadcast lookup
and uses the one below instead.
- Use the
NameServerLocator 's direct host mechanism. This only works if you know the host on which the NS is located.
The port argument is optional. If the NS has been started using a non-default port number you can use it to specify the port number.
locator = Pyro.naming.NameServerLocator()
ns = locator.getNS(host='hostname', port=7777)
If you specify the hostname yourself, the locator doesn't attempt to find the NS with the broadcast mechanism, and
therefore there is no lookup delay. Also you can specify a port number different from the default port.
If you set the PYRO_NS_HOSTNAME config option, the locator
automatically uses the specified host for a direct lookup. You don't
have to pass Pyro.config.PYRO_NS_HOSTNAME to the getNS method.
- Use the URI string the NS writes to a special file. This always works but is a bit more cumbersome, and your file should be copied or accessible across a network file system. Anyway, assume the NS writes to '
Pyro_NS_URI ':
uri = open('Pyro_NS_URI','r').read()
uri = Pyro.core.PyroURI(uri) # convert string to real URI object
ns = Pyro.naming.NameServerProxy(uri) # create a static proxy for the NS
... you can now invoke methods, such as ns.ping() ...
Note: The URI changes every time a Pyro server or object is created. You cannot use a previously written URI when you have restarted the server.
Note: pre 1.1 versions allowed you to use a dynamic proxy to access the NS. No longer! You must always use the static proxy! Using a dynamic proxy will screw up the name scheme and default name groups, unless your own code explicitly takes care of this (which is unlikely). This is cumbersome and the static proxy (Pyro.naming.NameServerProxy ) contains all necessary logic already. So just use that one. If you use the locator (see above) you will get a correct proxy automatically.
Note: the constructor of the NameServerProxy has an optional second argument: the connection authentication information. See the Security chapter for more information.
Introduced in Pyro 2.5, there is an even simpler way of using the Name Server
to look up objects by their name.
Instead of using the PYRO:// URIs that the Name Server returns,
and where you then get a proxy object for, you use another URI format.
This format is as follows:
PYRONAME://nshostname:port/objectname
The nshostname is the name of the host the Name Server is running on,
and port may be a non-default port the Name Server is listening on.
Both may be omitted.
objectname is the name of the object you want to find!
So, the next code fragment will find the NS using the default lookup mechanism, resolve the object name to a real URI,
create a proxy for that, and call a method:
Pyro.core.getProxyForURI('PYRONAME://:Test.MyObject').getQuote()
So we now have remote object method invocation in one statement :-)
There is one important point: each time a PYRONAME:// URI is used,
a lookup for the Name Server has to be performed, and then a lookup for the object name.
This is much slower than the regular method. However, once you've constructed
a proxy for this URI, no more lookups are performed.
There is another special URI, that bypasses the Name Server completely:
PYROLOC://hostname:port/objectname
This time hostname is required and is the name of the host that
your target Pyro object runs on. port may be a non-default PYRO port
the Pyro daemon is running on, and may be omitted.
objectname is the internal name for the Pyro object you want to access.
When you use this URI, the Name Server is bypassed and the target server is
contacted directly to get the regular URI for the desired object.
The advantage of this is that you don't have to have a Pyro Name Server running.
The disatvantages are obvious; you miss all the features of the Name Server
and you have to administrate server object names yourself somehow.
You must use the name that is passed to the connect method of the Daemon.
There is no hierarchical naming scheme because the Name Server is not used at all.
Once the object is found, the real URI is stored and no more lookups need to be done.
The next code fragment shows how to call a remote object, without requiring a Name Server to be present:
Pyro.core.getProxyForURI('PYROLOC://localhost:MyObject').getQuote()
Remember that your server does not have to rely on a Name Server when you want to use this mechanism.
When you enable Pyro logging, you might get a WARN that a Name Server is not specified. You can ignore this.
Please also see the "noNS" example, that shows how to use this URI,
and also how you could connect directly by using an URI string that comes off
the server.
Ok, you've got a proxy for the Name Server. Now what to do with it?
You've already seen the most important method: resolve .
There are more methods, see below. One very important thing to realize:
all names you supply must be absolute, i.e. ":Group.Objectname"
instead of just "Objectname". The NameServerProxy
that you'll usually be working with has some logic that takes care of this.
resolve(name)
- Look up the object with the given name and returns the Pyro URI.
(it will always return a real PyroURI object, not a string).
register(name, URI)
- Registers an object with the given name and the given Pyro URI.
The URI can be a PyroURI object or just a string.
unregister(name)
- Removes the object with the given name from the naming database.
ping()
- Does nothing, just to test if the Name Server is running.
list(groupname)
- Returns a list of the given group. If groupname is None, lists the root group.
The list contains tuples (name,type) where name is the object name,
and type is 0 for a naming group, and 1 for an object name.
flatlist()
- Returns a list of all objects in the naming database. The list contains
tuples (name, uri) where name is the absolute object name and uri is
the associated PyroURI object.
createGroup(name)
- Create a new empty naming group.
deleteGroup(name)
- Delete a naming group, including all its contents.
See the source code of the (x)nsc tools (nsc.py / xnsc.py ) for more info.
Important notice:
By default, there is no access control on the Name Server.
It is possible for anybody to remove and overwrite an existing registered object.
You must be very aware of this, because it is very easy to sneak a trojan in by
overwriting a name with a reference to the trojan object!
This free access is necessary for instance to be able to use the "nsc" tool without restriction.
|