If the osh configuration file is going to be used for database access, then it may contain a plaintext database password. It is therefore good practice to restrict access this file to, e.g. set permissions to 600.
from osh.config import *
Database and cluster configuration is done using field and slice notation. For example,
to specify that the sql command connects to
the family database as 'jao':
osh.sql.family.database = 'family'
osh.sql.family.user = 'jao'
Slice notation is also supported, e.g.
osh.sql['family'].user = 'jao'
This is useful in case a database or cluster name is known dynamically, or is not
a legal Python identifier.
osh sql family 'select count(*) from request' $
family is the name of a database profile, specified in .oshrc.
The profile specifies a module implementing the connect method of a DBAPI 2.0 driver, and
the arguments to the module's connect method, e.g.
osh.sql.family.driver = 'pg8000.dbapi'
osh.sql.family.host = 'localhost'
osh.sql.family.database = 'familydb'
osh.sql.family.user = 'jao'
osh.sql.family.password = 'l3tme1n'
This specification results in a connection being created
as pg8000.dbapi.connect(host = 'localhost', database = 'familydb',
user = 'jao', password = 'l3tme1n').
The DBAPI driver is not included with osh. It needs to be in your python environment, located on PYTHONPATH, in site-packages, or in a location specified by sitecustomize.py.
osh also provides access to postgres databases using the pygresql driver as follows:
osh.sql.family.dbtype = 'postgres'
osh.sql.family.host = 'localhost'
osh.sql.family.db = 'familydb'
osh.sql.family.user = 'jao'
osh.sql.family.password = 'l3tme1n'
A default database profile can be specified by assigning a value to osh.sql, e.g.
osh.sql = 'family'
If this is done, then the sql command can omit the database profile name, e.g.
osh sql 'select count(*) from request' $
osh @fred [ sql family 'select name, age from person' ] $
Each node of fred's cluster must
configure a database profile named family in its
.oshrc file.
On the local node (the one on which the above command is entered), the cluster fred must be configured, e.g.
osh.remote.fred.hosts = ['192.168.100.101',
'192.168.100.102',
'192.168.100.103']
Access to the cluster is done as root. If you want to connect as
some other user, specify the user as follows:
osh.remote.fred.user = 'zack'
Remote access is done using ssh, and osh cannot handle any prompts, e.g. for password
or a passphrase. If you can connect to a host silently using ssh, e.g. by setting
up an ssh agent, then that will work for osh. If you use the ssh -i option,
then the identity can be specified in .oshrc, e.g.
osh.remote.fred.identity = '~/.ssh/fred.pem'
(You can check your ssh connection using
the testssh command, e.g. osh @fred [ testssh ] $.)
When a remote command is run on a cluster, each row of output identifies the node that generated the output, e.g.
zack$ osh @fred [ sql family 'select name, age from person' ] $
('192.168.100.101', 'hannah', 15)
('192.168.100.101', 'julia', 10)
('192.168.100.102', 'alexander', 16)
('192.168.100.102', 'nathan', 15)
('192.168.100.102', 'zoe', 11)
('192.168.100.103', 'danica', 1)
The hosts part of a cluster specification can also be done using a dict, in which
the key is a name for the node, and the value is the IP address, e.g.
osh.remote.fred.hosts = {'101': '192.168.100.101',
'102': '192.168.100.102',
'103': '192.168.100.103'}
The node names are used in command output in place of IP addresses, e.g.
zack$ osh @fred [ sql familydb 'select name, age from person' ] $
('101', 'hannah', 15)
('101', 'julia', 10)
('102', 'alexander', 16)
('102', 'nathan', 15)
('102', 'zoe', 11)
('103', 'danica', 1)
These examples assume that each node of cluster fred has
a .oshrc file that configures a database profile
named family. It is also possible to configure database
access even when each node specifies a different database profile, e.g.
osh.remote.fred.hosts = {'101': {'host': '192.168.100.101', 'db_profile': 'db1'},
'102': {'host': '192.168.100.102', 'db_profile': 'db2'},
'103': {'host': '192.168.100.103', 'db_profile': 'db3'}}
With this configuration osh @fred [ sql 'select ...' ] ...
accesses db1 on node 101, db2 on node 102, and db3 on
node 103.
The complete rules for selecting a database profile are as follows:
zack$ osh gen 10 ^ f 'x: (x**2, x**3)' $
The same computation can be done by writing a function to compute squares and cubes:
def square_and_cube(x):
return x**2, x**3
and putting this function definition in .oshrc. Then, the osh
command above can be rewritten as:
zack$ osh gen 10 ^ f 'x: square_and_cube(x)' $
osh.path = ['/usr/local/foobar']
or the osh interpreter will not find xyz when used in an osh command sequence.
The value of osh.path is a list so that custom commands can be placed in any number of directories.