Typos, white-space, unused/missing imports, wrapping, PEP-8.

This commit is contained in:
Pedro Algarvio 2011-05-26 12:17:02 +01:00
parent 3f157549c2
commit 7ccb5e4cec
38 changed files with 262 additions and 194 deletions

52
README
View File

@ -1,12 +1,50 @@
What is Salt? What is Salt?
Were not just talking about NaCl. Were not just talking about NaCl.
Salt is a distributed remote execution system used to execute commands and query data. It was developed in order to bring the best solutions found in the world of remote execution together and make them better, faster and more malleable. Salt accomplishes this via its ability to handle larger loads of information, and not just dozens, but hundreds or even thousands of individual servers, handle them quickly and through a simple and manageable interface. Salt is a distributed remote execution system used to execute commands and query
Versatility between massive scale deployments and smaller systems may seem daunting, but Salt is very simple to set up and maintain, regardless of the size of the project. The architecture of Salt is designed to work with any number of servers, from a handful of local network systems to international deployments across disparate datacenters. The topology is a simple server/client model with the needed functionality built into a single set of daemons. While the default configuration will work with little to no modification, salt can be fine tuned to meet specific needs. data. It was developed in order to bring the best solutions found in the world
The core function of salt is to enable remote commands to be called in parallel rather than in serial, to use a secure and encrypted protocol, the smallest and fastest network payloads possible and with a simple programmer interface. Salt also introduces more granular controls to the realm of remote execution, allowing for commands to be executed in parallel and for systems to be targeted based on more than just hostname, but by system properties. of remote execution together and make them better, faster and more malleable.
Salt takes advantage of a number of technologies and techniques. The networking layer is built with the excellent zeromq networking library, so salt itself contains a viable, and transparent, amq broker inside the daemon. Salt uses public keys for authentication with the master daemon, then uses faster aes encryption for payload communication, this means that authentication and encryption are also built into Salt. Salt takes advantage of communication via python pickles, enabling fast and light network traffic.
In order to allow for simple expansion, Salt execution routines can be written as plain python modules, and the data collected from salt executions can be sent back to the master server, or to any arbitrary program. Salt can be called from a simple python api, or from the command line, so that salt can be used to execute one-off commands as well as operate as an integral part of a larger application.
The result is a system that can execute commands across groups of varying size, from very few to very many servers at considerably high speed. A system that is very fast, easy to set up and amazingly malleable, able to suit the needs of any number of servers working within the same system. Salts unique architecture brings together the best of the remote execution world, amplifies its capabilities and expands its range, resulting in this system that is as versatile as it is practical, able to suit any network.
Salt is developed under the Apache 2.0 licence, and can be used for open and proprietary projects. Please submit your expansions to back so that we can all benefit together as Salt grows. So, please feel free to sprinkle some of this around your systems and let the deliciousness come forth.
Salt accomplishes this via its ability to handle larger loads of information,
and not just dozens, but hundreds or even thousands of individual servers,
handle them quickly and through a simple and manageable interface.
Versatility between massive scale deployments and smaller systems may seem
daunting, but Salt is very simple to set up and maintain, regardless of the
size of the project. The architecture of Salt is designed to work with any
number of servers, from a handful of local network systems to international
deployments across disparate data-centers. The topology is a simple server/client
model with the needed functionality built into a single set of daemons.
While the default configuration will work with little to no modification, salt
can be fine tuned to meet specific needs.
The core function of salt is to enable remote commands to be called in parallel
rather than in serial, to use a secure and encrypted protocol, the smallest and
fastest network payloads possible and with a simple programmer interface.
Salt also introduces more granular controls to the realm of remote execution,
allowing for commands to be executed in parallel and for systems to be targeted
based on more than just hostname, but by system properties.
Salt takes advantage of a number of technologies and techniques. The networking
layer is built with the excellent zeromq networking library, so salt itself
contains a viable, and transparent, amq broker inside the daemon. Salt uses
public keys for authentication with the master daemon, then uses faster aes
encryption for payload communication, this means that authentication and
encryption are also built into Salt. Salt takes advantage of communication via
python pickles, enabling fast and light network traffic.
In order to allow for simple expansion, Salt execution routines can be written
as plain python modules, and the data collected from salt executions can be sent
back to the master server, or to any arbitrary program. Salt can be called from
a simple python api, or from the command line, so that salt can be used to
execute one-off commands as well as operate as an integral part of a larger
application.
The result is a system that can execute commands across groups of varying size,
from very few to very many servers at considerably high speed. A system that is
very fast, easy to set up and amazingly malleable, able to suit the needs of any
number of servers working within the same system. Salts unique architecture
brings together the best of the remote execution world, amplifies its
capabilities and expands its range, resulting in this system that is as
versatile as it is practical, able to suit any network.
Salt is developed under the Apache 2.0 licence, and can be used for open and
proprietary projects. Please submit your expansions to back so that we can all
benefit together as Salt grows. So, please feel free to sprinkle some of this
around your systems and let the deliciousness come forth.

View File

@ -24,23 +24,28 @@ The timeout in seconds to wait for replies from the salt minions.
.TP .TP
-E, --pcre -E, --pcre
The target expresion will be interpereted as a pcre regular expression rather than a shell glob. The target expression will be interpreted as a pcre regular expression rather than a shell glob.
.TP .TP
-L, --list -L, --list
The target expression will be interpereted as a comma delimited list, example: server1.foo.bar,server2.foo.bar,example7.quo.qux The target expression will be interpreted as a comma delimited list,
example: server1.foo.bar,server2.foo.bar,example7.quo.qux
.TP .TP
-G, --grain -G, --grain
The target expression matches values returned by the salt grains system on the minions. The target expresion is in the format of '<grain value>:<pcre regular expresion>'; example: 'os:Arch.*' The target expression matches values returned by the salt grains system on the
minions. The target expression is in the format of '<grain value>:<pcre regular expression>';
example: 'os:Arch.*'
.TP .TP
-Q, --query -Q, --query
Execute a salt command query, this can be used to find the results os a previous function call: -Q test.echo') Execute a salt command query, this can be used to find the results os a previous
function call: -Q test.echo')
.TP .TP
-c CONFIG, --config=CONFIG -c CONFIG, --config=CONFIG
The location of the salt master configuration file, the salt master settings are required to know where the connections are; default=/etc/salt/master The location of the salt master configuration file, the salt master settings are
required to know where the connections are; default=/etc/salt/master
.SH AUTHORS .SH AUTHORS
Thomas S. Hatch <thatch@gmail.com> Thomas S. Hatch <thatch@gmail.com>

View File

@ -32,7 +32,8 @@ Accepts all pending public keys.
.TP .TP
-c CONFIG, --config=CONFIG -c CONFIG, --config=CONFIG
The master configuration file needs to be read to determine where the salt keys are stored via the pki_dir configuration value; default=/etc/salt/master The master configuration file needs to be read to determine where the salt keys
are stored via the pki_dir configuration value; default=/etc/salt/master
.SH AUTHORS .SH AUTHORS

View File

@ -1,13 +1,14 @@
.TH salt-minion 1 "May 2011" "salt-minion 0.8.7" "salt-minion Manual" .TH salt-minion 1 "May 2011" "salt-minion 0.8.7" "salt-minion Manual"
.SH NAME .SH NAME
salt-minion \- The salt minion daemon, recieves commands from a remote salt master. salt-minion \- The salt minion daemon, receives commands from a remote salt master.
.SH SYNOPSIS .SH SYNOPSIS
.B salt-minion [ options ] .B salt-minion [ options ]
.SH DESCRIPTION .SH DESCRIPTION
The salt minion recieves commands from the central salt master and replies with the results of said commands. The salt minion receives commands from the central salt master and replies with
the results of said commands.
.SH OPTIONS .SH OPTIONS
.TP .TP

View File

@ -13,7 +13,8 @@ salt \- Parallel remote execution system
.B salt -Q test.ping .B salt -Q test.ping
.SH DESCRIPTION .SH DESCRIPTION
Salt allows for commands to be executed across a swath of remote systems in parallel. This means that remote systems can be both controleed and querried with ease. Salt allows for commands to be executed across a swath of remote systems in parallel.
This means that remote systems can be both controlled and queried with ease.
.SH OPTIONS .SH OPTIONS
.TP .TP
@ -26,23 +27,29 @@ The timeout in seconds to wait for replies from the salt minions.
.TP .TP
-E, --pcre -E, --pcre
The target expresion will be interpereted as a pcre regular expression rather than a shell glob. The target expression will be interpreted as a pcre regular expression rather than
a shell glob.
.TP .TP
-L, --list -L, --list
The target expression will be interpereted as a comma delimited list, example: server1.foo.bar,server2.foo.bar,example7.quo.qux The target expression will be interpreted as a comma delimited list,
example: server1.foo.bar,server2.foo.bar,example7.quo.qux
.TP .TP
-G, --grain -G, --grain
The target expression matches values returned by the salt grains system on the minions. The target expresion is in the format of '<grain value>:<pcre regular expresion>'; example: 'os:Arch.*' The target expression matches values returned by the salt grains system on the
minions. The target expression is in the format of '<grain value>:<pcre regular expression>';
example: 'os:Arch.*'
.TP .TP
-Q, --query -Q, --query
Execute a salt command query, this can be used to find the results os a previous function call: -Q test.echo') Execute a salt command query, this can be used to find the results os a previous
function call: -Q test.echo')
.TP .TP
-c CONFIG, --config=CONFIG -c CONFIG, --config=CONFIG
The location of the salt master configuration file, the salt master settings are required to know where the connections are; default=/etc/salt/master The location of the salt master configuration file, the salt master settings are
required to know where the connections are; default=/etc/salt/master
.SH AUTHORS .SH AUTHORS
Thomas S. Hatch <thatch@gmail.com> Thomas S. Hatch <thatch@gmail.com>

View File

@ -11,13 +11,17 @@ salt \- The salt distributed system controller
.B salt [options] .B salt [options]
.SH DESCRIPTION .SH DESCRIPTION
Salt is a powerful remote execution manager that can be used to administer servers in a fast and efficient way. Salt is a powerful remote execution manager that can be used to administer
servers in a fast and efficient way.
.SH SETTING UP SALT .SH SETTING UP SALT
The Salt system setup is amazingly simple, as this is one of the central design goals of Salt. Setting up Salt only requires that the salt master be running and the salt minions point to the salt master. The Salt system setup is amazingly simple, as this is one of the central design
goals of Salt. Setting up Salt only requires that the salt master be running and
the salt minions point to the salt master.
.SS INSTALATION .SS INSTALATION
The salt install is simple, for many distributions pakages should be available for download, or salt can be installed via the python packaging tools. The salt install is simple, for many distributions packages should be available
for download, or salt can be installed via the python packaging tools.
.P .P
Installing salt from source is a simple task, download the latest source tarball from Installing salt from source is a simple task, download the latest source tarball from
.URL "https://github.com/thatch45/salt/downloads" .URL "https://github.com/thatch45/salt/downloads"
@ -31,15 +35,16 @@ Next untar the download and run the python setup:
# python2 setup.py install # python2 setup.py install
.SS SALT DEPENDENCIES .SS SALT DEPENDENCIES
This is a basic python setup, nothing fancy. Salt does require a number of dependencies though, all of which should be available in your distribution's packages. This is a basic python setup, nothing fancy. Salt does require a number of
dependencies though, all of which should be available in your distribution's packages.
.TP .TP
\(bu \(bu
python2.7 - python2.6 should work, but it is untested python2.7 - python2.6 should work, but it is untested
.TP .TP
\(bu \(bu
pyzmq - zeromq python bindings pyzmq - zeromq python bindings
.TP .TP
\(bu \(bu
python-m2crypto - Crypto backend python-m2crypto - Crypto backend
.TP .TP
@ -50,7 +55,9 @@ python-yaml - Reading configuration files
pycrypto - Another crypto backend pycrypto - Another crypto backend
.SS RUNNING SALT .SS RUNNING SALT
To run Salt you need to ensure that a master and a minion are running and referencing each other. Starting the master and minion daemons is done with the respective commands. To run Salt you need to ensure that a master and a minion are running and
referencing each other. Starting the master and minion daemons is done with the
respective commands.
On the salt master server: On the salt master server:

View File

@ -10,7 +10,7 @@ import salt.config
def verify_env(dirs): def verify_env(dirs):
''' '''
Verify that the named direcotries are in place and that the environment Verify that the named directories are in place and that the environment
can shake the salt can shake the salt
''' '''
for dir_ in dirs: for dir_ in dirs:

View File

@ -25,7 +25,7 @@ class SaltCMD(object):
''' '''
def __init__(self): def __init__(self):
''' '''
Cretae a SaltCMD object Create a SaltCMD object
''' '''
self.opts = self.__parse() self.opts = self.__parse()
@ -34,7 +34,7 @@ class SaltCMD(object):
Parse the command line Parse the command line
''' '''
parser = optparse.OptionParser() parser = optparse.OptionParser()
parser.add_option('-t', parser.add_option('-t',
'--timeout', '--timeout',
default=5, default=5,
@ -63,7 +63,7 @@ class SaltCMD(object):
help='Instead of using shell globs to evaluate the target'\ help='Instead of using shell globs to evaluate the target'\
+ ' use a grain value to identify targets, the syntax'\ + ' use a grain value to identify targets, the syntax'\
+ ' for the target is the grain key followed by a pcre'\ + ' for the target is the grain key followed by a pcre'\
+ ' regular expresion:\n"os:Arch.*"') + ' regular expression:\n"os:Arch.*"')
parser.add_option('-X', parser.add_option('-X',
'--exsel', '--exsel',
default=False, default=False,
@ -97,7 +97,7 @@ class SaltCMD(object):
action='store_true', action='store_true',
dest='raw_out', dest='raw_out',
help='Print the output from the salt command in raw python'\ help='Print the output from the salt command in raw python'\
+ ' form, this is suitible for re-reading the output into'\ + ' form, this is suitable for re-reading the output into'\
+ ' an executing python script with eval.') + ' an executing python script with eval.')
if JSON: if JSON:
parser.add_option('--json-out', parser.add_option('--json-out',
@ -179,7 +179,7 @@ class SaltCMD(object):
args.append('exsel') args.append('exsel')
else: else:
args.append('glob') args.append('glob')
if self.opts['return']: if self.opts['return']:
args.append(self.opts['return']) args.append(self.opts['return'])
ret = local.cmd(*args) ret = local.cmd(*args)
@ -224,7 +224,7 @@ class SaltCP(object):
Parse the command line Parse the command line
''' '''
parser = optparse.OptionParser() parser = optparse.OptionParser()
parser.add_option('-t', parser.add_option('-t',
'--timeout', '--timeout',
default=5, default=5,
@ -253,7 +253,7 @@ class SaltCP(object):
help='Instead of using shell globs to evaluate the target'\ help='Instead of using shell globs to evaluate the target'\
+ ' use a grain value to identify targets, the syntax'\ + ' use a grain value to identify targets, the syntax'\
+ ' for the target is the grains key followed by a pcre'\ + ' for the target is the grains key followed by a pcre'\
+ ' regular expresion:\n"os:Arch.*"') + ' regular expression:\n"os:Arch.*"')
parser.add_option('-c', parser.add_option('-c',
'--config', '--config',
default='/etc/salt/master', default='/etc/salt/master',
@ -315,7 +315,7 @@ class SaltKey(object):
default=False, default=False,
action='store_true', action='store_true',
help='List all public keys') help='List all public keys')
parser.add_option('-a', parser.add_option('-a',
'--accept', '--accept',
dest='accept', dest='accept',

View File

@ -1,5 +1,5 @@
''' '''
The caller module is used as a frontend to manage direct calls to the salt The caller module is used as a front-end to manage direct calls to the salt
minion modules. minion modules.
''' '''
# Import python modules # Import python modules

View File

@ -1,7 +1,7 @@
''' '''
The cp module is used to execute the logic used by the salt-cp command The cp module is used to execute the logic used by the salt-cp command
line application, salt-cp is NOT intended to broadcast large files, it is line application, salt-cp is NOT intended to broadcast large files, it is
intened to handle text files. intended to handle text files.
Salt-cp can be used to distribute configuration files Salt-cp can be used to distribute configuration files
''' '''
# Import python modules # Import python modules
@ -73,7 +73,7 @@ class SaltCP(object):
args.append('list') args.append('list')
elif self.opts['grain']: elif self.opts['grain']:
args.append('grain') args.append('grain')
ret = local.cmd(*args) ret = local.cmd(*args)
print yaml.dump(ret) print yaml.dump(ret)

View File

@ -1,6 +1,6 @@
''' '''
The client module is used to create a client connection to the publisher The client module is used to create a client connection to the publisher
The data structurte needs to be: The data structure needs to be:
{'enc': 'clear', {'enc': 'clear',
'load': {'fun': '<mod.callable>', 'load': {'fun': '<mod.callable>',
'arg':, ('arg1', 'arg2', ...), 'arg':, ('arg1', 'arg2', ...),
@ -10,17 +10,17 @@ The data structurte needs to be:
# The components here are simple, and they need to be and stay simple, we # The components here are simple, and they need to be and stay simple, we
# want a client to have 3 external concerns, and maybe a forth configurable # want a client to have 3 external concerns, and maybe a forth configurable
# option. # option.
# The concers are # The concerns are
# 1. Who executes the command? # 1. Who executes the command?
# 2. what is the function being run? # 2. what is the function being run?
# 3. What arguments need to be passed to the function? # 3. What arguments need to be passed to the function?
# 4. How long do we wait for all of the replies? # 4. How long do we wait for all of the replies?
# #
# Next there are a number of tasks, first we need some kind of authentication # Next there are a number of tasks, first we need some kind of authentication
# This Client initially will be the master root client, which will run as the # This Client initially will be the master root client, which will run as the
# root user on the master server. # root user on the master server.
# BUT we also want a client to be able to work over the network, so that # BUT we also want a client to be able to work over the network, so that
# controllers can exist within disperate applicaitons. # controllers can exist within disparate applications.
# The problem is that this is a security nightmare, so I am going to start # The problem is that this is a security nightmare, so I am going to start
# small, and only start with the ability to execute salt commands locally. # small, and only start with the ability to execute salt commands locally.
# This means that the primary client to build is, the LocalClient # This means that the primary client to build is, the LocalClient
@ -90,7 +90,7 @@ class LocalClient(object):
def _check_pcre_minions(self, expr): def _check_pcre_minions(self, expr):
''' '''
Return the minions found by looking via regular expresions Return the minions found by looking via regular expressions
''' '''
ret = set() ret = set()
cwd = os.getcwd() cwd = os.getcwd()
@ -184,10 +184,10 @@ class LocalClient(object):
'grain': self._check_grain_minions, 'grain': self._check_grain_minions,
'exsel': self._check_grain_minions, 'exsel': self._check_grain_minions,
}[expr_form](expr) }[expr_form](expr)
def pub(self, tgt, fun, arg=(), expr_form='glob', ret=''): def pub(self, tgt, fun, arg=(), expr_form='glob', ret=''):
''' '''
Take the required arguemnts and publish the given command. Take the required arguments and publish the given command.
Arguments: Arguments:
tgt: tgt:
The tgt is a regex or a glob used to match up the ids on The tgt is a regex or a glob used to match up the ids on
@ -195,11 +195,11 @@ class LocalClient(object):
all of the minions and then the minions determine if the all of the minions and then the minions determine if the
command is for them based on the tgt value. command is for them based on the tgt value.
fun: fun:
The function nane to be called on the remote host(s), this must The function name to be called on the remote host(s), this must
be a string in the format "<modulename>.<function name>" be a string in the format "<modulename>.<function name>"
arg: arg:
The arg option needs to be a tuple of arguments to pass to the The arg option needs to be a tuple of arguments to pass to the
calling function, if left blank calling function, if left blank
Returns: Returns:
jid: jid:
A string, as returned by the publisher, which is the job id, A string, as returned by the publisher, which is the job id,
@ -207,7 +207,7 @@ class LocalClient(object):
minions: minions:
A set, the targets that the tgt passed should match. A set, the targets that the tgt passed should match.
''' '''
# Run a check_minions, if no minons match return False # Run a check_minions, if no minions match return False
# format the payload - make a function that does this in the payload # format the payload - make a function that does this in the payload
# module # module
# make the zmq client # make the zmq client
@ -229,8 +229,7 @@ class LocalClient(object):
# Prep zmq # Prep zmq
context = zmq.Context() context = zmq.Context()
socket = context.socket(zmq.REQ) socket = context.socket(zmq.REQ)
socket.connect('tcp://' + self.opts['interface'] + ':'\ socket.connect('tcp://%(interface)s:%(ret_port)s' % self.opts)
+ str(self.opts['ret_port']))
socket.send(package) socket.send(package)
payload = salt.payload.unpackage(socket.recv()) payload = salt.payload.unpackage(socket.recv())
return {'jid': payload['load']['jid'], return {'jid': payload['load']['jid'],

View File

@ -45,7 +45,7 @@ def minion_config(path):
opts['master_uri'] = 'tcp://' + opts['master'] + ':'\ opts['master_uri'] = 'tcp://' + opts['master'] + ':'\
+ str(opts['master_port']) + str(opts['master_port'])
# Enableing open mode requires that the value be set to True, and nothing # Enabling open mode requires that the value be set to True, and nothing
# else! # else!
if opts['open_mode']: if opts['open_mode']:
if opts['open_mode'] == True: if opts['open_mode'] == True:
@ -91,7 +91,7 @@ def master_config(path):
opts['aes'] = salt.crypt.Crypticle.generate_key_string() opts['aes'] = salt.crypt.Crypticle.generate_key_string()
# Enableing open mode requires that the value be set to True, and nothing # Enabling open mode requires that the value be set to True, and nothing
# else! # else!
if opts['open_mode']: if opts['open_mode']:
if opts['open_mode'] == True: if opts['open_mode'] == True:

View File

@ -48,7 +48,7 @@ class MasterKeys(dict):
def __get_priv_key(self): def __get_priv_key(self):
''' '''
Retruns a private key object for the master Returns a private key object for the master
''' '''
key = None key = None
try: try:
@ -89,7 +89,7 @@ class Auth(object):
def get_priv_key(self): def get_priv_key(self):
''' '''
Retruns a private key object for the minion Returns a private key object for the minion
''' '''
key = None key = None
try: try:
@ -107,7 +107,7 @@ class Auth(object):
def minion_sign_in_payload(self): def minion_sign_in_payload(self):
''' '''
Generates the payload used to autnenticate with the master server. This Generates the payload used to authenticate with the master server. This
payload consists of the passed in id_ and the ssh public key to encrypt payload consists of the passed in id_ and the ssh public key to encrypt
the AES key sent back form the master. the AES key sent back form the master.
''' '''
@ -129,7 +129,7 @@ class Auth(object):
Pass in the encrypted aes key. Pass in the encrypted aes key.
Returns the decrypted aes seed key, a string Returns the decrypted aes seed key, a string
''' '''
log.info('Decypting the current master AES key') log.info('Decrypting the current master AES key')
key = self.get_priv_key() key = self.get_priv_key()
return key.private_decrypt(aes, 4) return key.private_decrypt(aes, 4)
@ -137,7 +137,7 @@ class Auth(object):
''' '''
Takes the master pubkey and compares it to the saved master pubkey, Takes the master pubkey and compares it to the saved master pubkey,
the token is encrypted with the master private key and must be the token is encrypted with the master private key and must be
decrypted sucessfully to verify that the master has been connected to. decrypted successfully to verify that the master has been connected to.
The token must decrypt with the public key, and it must say: The token must decrypt with the public key, and it must say:
'salty bacon' 'salty bacon'
returns a bool returns a bool
@ -274,7 +274,7 @@ class Crypticle(object):
def loads(self, data, pickler=pickle): def loads(self, data, pickler=pickle):
''' '''
decrypt and unpickle a python object decrypt and un-pickle a python object
''' '''
data = self.decrypt(data) data = self.decrypt(data)
# simple integrity check to verify that we got meaningful data # simple integrity check to verify that we got meaningful data
@ -294,7 +294,7 @@ class SAuth(object):
def __authenticate(self): def __authenticate(self):
''' '''
Authenticate with the master, this method breaks the functional Authenticate with the master, this method breaks the functional
pardigmn, it will update the master information from a fresh sign in, paradigm, it will update the master information from a fresh sign in,
signing in can occur as often as needed to keep up with the revolving signing in can occur as often as needed to keep up with the revolving
master aes key. master aes key.
''' '''

View File

@ -127,7 +127,7 @@ def os_data():
grains['os'] = kernel grains['os'] = kernel
# Load the virtual machine info # Load the virtual machine info
grains.update(_virtual(grains)) grains.update(_virtual(grains))
grains.update(_ps(grains)) grains.update(_ps(grains))
return grains return grains

View File

@ -81,9 +81,9 @@ def call(fun, args=[], dirs=[]):
class Loader(object): class Loader(object):
''' '''
Used to load in arbitrairy modules from a directory, the Loader can also be Used to load in arbitrary modules from a directory, the Loader can also be
used to only load specific functions from a directory, or to call modules used to only load specific functions from a directory, or to call modules
in an arbitrairy directory directly. in an arbitrary directory directly.
''' '''
def __init__(self, module_dirs, opts={}): def __init__(self, module_dirs, opts={}):
self.module_dirs = module_dirs self.module_dirs = module_dirs
@ -255,7 +255,7 @@ class Loader(object):
def gen_grains(self): def gen_grains(self):
''' '''
Read the grains directory and execute all of the public callable Read the grains directory and execute all of the public callable
members. then verify that the returns are python dicts and return a members. then verify that the returns are python dict's and return a
dict containing all of the returned values. dict containing all of the returned values.
''' '''
grains = {} grains = {}

View File

@ -7,7 +7,7 @@
:copyright: © 2011 :email:`Pedro Algarvio (pedro@algarvio.me)` :copyright: © 2011 :email:`Pedro Algarvio (pedro@algarvio.me)`
:license: Apache Version 2.0, see LICENSE for more details. :license: Apache 2.0, see LICENSE for more details.
""" """
import logging import logging

View File

@ -19,7 +19,7 @@ import salt.utils
import salt.crypt import salt.crypt
import salt.payload import salt.payload
import salt.client import salt.client
# Import cryptogrogphy modules # Import cryptography modules
from M2Crypto import RSA from M2Crypto import RSA
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -61,7 +61,7 @@ class Master(object):
class Publisher(multiprocessing.Process): class Publisher(multiprocessing.Process):
''' '''
The publihing interface, a simple zeromq publisher that sends out the The publishing interface, a simple zeromq publisher that sends out the
commands. commands.
''' '''
def __init__(self, opts): def __init__(self, opts):
@ -115,7 +115,7 @@ class ReqServer():
A key needs to be placed in the filesystem with permissions 0400 so A key needs to be placed in the filesystem with permissions 0400 so
clients are required to run as root. clients are required to run as root.
''' '''
log.info('Preparing the root key for local comunication') log.info('Preparing the root key for local communication')
keyfile = os.path.join(self.opts['cachedir'], '.root_key') keyfile = os.path.join(self.opts['cachedir'], '.root_key')
key = salt.crypt.Crypticle.generate_key_string() key = salt.crypt.Crypticle.generate_key_string()
if os.path.isfile(keyfile): if os.path.isfile(keyfile):
@ -139,7 +139,7 @@ class ReqServer():
m_worker.start() m_worker.start()
out_socket = self.context.socket(zmq.REQ) out_socket = self.context.socket(zmq.REQ)
out_socket.connect('tcp://127.0.0.1:' + str(work_port)) out_socket.connect('tcp://127.0.0.1:%s' % work_port)
while True: while True:
package = in_socket.recv() package = in_socket.recv()
@ -188,7 +188,7 @@ class MWorker(multiprocessing.Process):
''' '''
context = zmq.Context(1) context = zmq.Context(1)
socket = context.socket(zmq.REP) socket = context.socket(zmq.REP)
socket.bind('tcp://127.0.0.1:' + self.port) socket.bind('tcp://127.0.0.1:%s' % self.port)
while True: while True:
package = socket.recv() package = socket.recv()
@ -202,8 +202,9 @@ class MWorker(multiprocessing.Process):
job id directory. job id directory.
''' '''
jid_root = os.path.join(self.opts['cachedir'], 'jobs') jid_root = os.path.join(self.opts['cachedir'], 'jobs')
jid = datetime.datetime.strftime(datetime.datetime.now(), jid = datetime.datetime.strftime(
'%Y%m%d%H%M%S%f') datetime.datetime.now(), '%Y%m%d%H%M%S%f'
)
jid_dir = os.path.join(jid_root, jid) jid_dir = os.path.join(jid_root, jid)
if not os.path.isdir(jid_dir): if not os.path.isdir(jid_dir):
os.makedirs(jid_dir) os.makedirs(jid_dir)
@ -225,21 +226,21 @@ class MWorker(multiprocessing.Process):
''' '''
Take care of a cleartext command Take care of a cleartext command
''' '''
log.info('Clear payload recieved with command %(cmd)s', load) log.info('Clear payload received with command %(cmd)s', load)
return getattr(self, load['cmd'])(load) return getattr(self, load['cmd'])(load)
def _handle_pub(self, load): def _handle_pub(self, load):
''' '''
Handle a command sent via a public key pair Handle a command sent via a public key pair
''' '''
log.info('Pubkey payload recieved with command %(cmd)s', load) log.info('Pubkey payload received with command %(cmd)s', load)
def _handle_aes(self, load): def _handle_aes(self, load):
''' '''
Handle a command sent via an aes key Handle a command sent via an aes key
''' '''
data = self.crypticle.loads(load) data = self.crypticle.loads(load)
log.info('AES payload recieved with command %(cmd)s', load) log.info('AES payload received with command %(cmd)s', load)
return getattr(self, data['cmd'])(data) return getattr(self, data['cmd'])(data)
def _auth(self, load): def _auth(self, load):
@ -247,7 +248,7 @@ class MWorker(multiprocessing.Process):
Authenticate the client, use the sent public key to encrypt the aes key Authenticate the client, use the sent public key to encrypt the aes key
which was generated at start up which was generated at start up
''' '''
# 1. Verify that the key we are recieving matches the stored key # 1. Verify that the key we are receiving matches the stored key
# 2. Store the key if it is not there # 2. Store the key if it is not there
# 3. make an rsa key with the pub key # 3. make an rsa key with the pub key
# 4. encrypt the aes key as an encrypted pickle # 4. encrypt the aes key as an encrypted pickle
@ -326,7 +327,7 @@ class MWorker(multiprocessing.Process):
def _serve_file(self, load): def _serve_file(self, load):
''' '''
Return a chunk from a file based on the data recieved Return a chunk from a file based on the data received
''' '''
if not load.has_key('path') or not load.has_key('loc'): if not load.has_key('path') or not load.has_key('loc'):
return False return False
@ -368,7 +369,7 @@ class MWorker(multiprocessing.Process):
jid_dir = os.path.join(self.opts['cachedir'], 'jobs', load['jid']) jid_dir = os.path.join(self.opts['cachedir'], 'jobs', load['jid'])
if not os.path.isdir(jid_dir): if not os.path.isdir(jid_dir):
log.error( log.error(
'An inconsistency occured, a job was recieved with a job id ' 'An inconsistency occurred, a job was received with a job id '
'that is not present on the master: %(jid)s', load 'that is not present on the master: %(jid)s', load
) )
return False return False
@ -380,7 +381,7 @@ class MWorker(multiprocessing.Process):
def _send_cluster(self): def _send_cluster(self):
''' '''
Send the cluser data out Send the cluster data out
''' '''
log.debug('Sending out cluster data') log.debug('Sending out cluster data')
ret = self.local.cmd(self.opts['cluster_masters'], ret = self.local.cmd(self.opts['cluster_masters'],
@ -430,7 +431,7 @@ class MWorker(multiprocessing.Process):
payload['load'] = self.crypticle.dumps(load) payload['load'] = self.crypticle.dumps(load)
context = zmq.Context(1) context = zmq.Context(1)
pub_sock = context.socket(zmq.PUSH) pub_sock = context.socket(zmq.PUSH)
pub_sock.connect('tcp://127.0.0.1:' + self.opts['publish_pull_port']) pub_sock.connect('tcp://127.0.0.1:%(publish_pull_port)s' % self.opts)
pub_sock.send(salt.payload.package(payload)) pub_sock.send(salt.payload.package(payload))
return {'enc': 'clear', return {'enc': 'clear',
'load': {'jid': jid}} 'load': {'jid': jid}}

View File

@ -36,7 +36,7 @@ log = logging.getLogger(__name__)
class Minion(object): class Minion(object):
''' '''
This class instanciates a minion, runs connections for a minion, and loads This class instantiates a minion, runs connections for a minion, and loads
all of the functions into the minion all of the functions into the minion
''' '''
def __init__(self, opts): def __init__(self, opts):
@ -85,7 +85,7 @@ class Minion(object):
def _handle_aes(self, load): def _handle_aes(self, load):
''' '''
Takes the aes encrypted load, decypts is and runs the encapsulated Takes the aes encrypted load, decrypts is and runs the encapsulated
instructions instructions
''' '''
data = None data = None
@ -117,24 +117,32 @@ class Minion(object):
def _handle_clear(self, load): def _handle_clear(self, load):
''' '''
Handle unencrypted transmisions Handle un-encrypted transmissions
''' '''
pass pass
def _handle_decoded_payload(self, data): def _handle_decoded_payload(self, data):
''' '''
Override this method if you wish to handle the decoded data diferently. Override this method if you wish to handle the decoded data differently.
''' '''
if self.opts['multiprocessing']: if self.opts['multiprocessing']:
if type(data['fun']) == type(list()): if type(data['fun']) == type(list()):
multiprocessing.Process(target=lambda: self._thread_multi_return(data)).start() multiprocessing.Process(
target=lambda: self._thread_multi_return(data)
).start()
else: else:
multiprocessing.Process(target=lambda: self._thread_return(data)).start() multiprocessing.Process(
target=lambda: self._thread_return(data)
).start()
else: else:
if type(data['fun']) == type(list()): if type(data['fun']) == type(list()):
threading.Thread(target=lambda: self._thread_multi_return(data)).start() threading.Thread(
target=lambda: self._thread_multi_return(data)
).start()
else: else:
threading.Thread(target=lambda: self._thread_return(data)).start() threading.Thread(
target=lambda: self._thread_return(data)
).start()
def _glob_match(self, tgt): def _glob_match(self, tgt):
''' '''
@ -163,7 +171,7 @@ class Minion(object):
def _grain_match(self, tgt): def _grain_match(self, tgt):
''' '''
Reads in the grains regular expresion match Reads in the grains regular expression match
''' '''
comps = tgt.split(':') comps = tgt.split(':')
return bool(re.match(comps[1], self.opts['grains'][comps[0]])) return bool(re.match(comps[1], self.opts['grains'][comps[0]]))
@ -206,7 +214,7 @@ class Minion(object):
def _thread_multi_return(self, data): def _thread_multi_return(self, data):
''' '''
This methos should be used as a threading target, start the actual This method should be used as a threading target, start the actual
minion side execution. minion side execution.
''' '''
ret = {'return': {}} ret = {'return': {}}
@ -262,7 +270,7 @@ class Minion(object):
def authenticate(self): def authenticate(self):
''' '''
Authenticate with the master, this method breaks the functional Authenticate with the master, this method breaks the functional
pardigmn, it will update the master information from a fresh sign in, paradigm, it will update the master information from a fresh sign in,
signing in can occur as often as needed to keep up with the revolving signing in can occur as often as needed to keep up with the revolving
master aes key. master aes key.
''' '''
@ -271,7 +279,7 @@ class Minion(object):
while True: while True:
creds = auth.sign_in() creds = auth.sign_in()
if creds != 'retry': if creds != 'retry':
log.info('Authentication with master sucessful!') log.info('Authentication with master successful!')
break break
log.info('Waiting for minion key to be accepted by the master.') log.info('Waiting for minion key to be accepted by the master.')
time.sleep(10) time.sleep(10)

View File

@ -1,5 +1,5 @@
''' '''
Specilized routines used by the butter cloud component Specialized routines used by the butter cloud component
''' '''
# Import salt modules # Import salt modules
import virt import virt
@ -76,7 +76,7 @@ def _gen_pin_drives(pins):
def _apply_overlay(vda, instance): def _apply_overlay(vda, instance):
''' '''
Use libguestfs to apply the overlay inder the specified instance to the Use libguestfs to apply the overlay under the specified instance to the
specified vda specified vda
''' '''
overlay = os.path.join(instance, 'overlay') overlay = os.path.join(instance, 'overlay')

View File

@ -3,6 +3,7 @@ Minion side functions for salt-cp
''' '''
# Import python libs # Import python libs
import os import os
import hashlib
# Import salt libs # Import salt libs
import salt.crypt import salt.crypt
@ -14,7 +15,7 @@ def recv(files, dest):
''' '''
Used with salt-cp, pass the files dict, and the destination. Used with salt-cp, pass the files dict, and the destination.
This function recieves small fast copy files from the master via salt-cp This function receives small fast copy files from the master via salt-cp
''' '''
ret = {} ret = {}
for path, data in files.items(): for path, data in files.items():
@ -67,7 +68,7 @@ def get_file(path, dest):
def cache_files(paths): def cache_files(paths):
''' '''
Used to gather many files from the master, the gathered files will be Used to gather many files from the master, the gathered files will be
saved in the minion cachedir reflective to the paths retrived from the saved in the minion cachedir reflective to the paths retrieved from the
master. master.
''' '''
auth = salt.crypt.SAuth(__opts__) auth = salt.crypt.SAuth(__opts__)

View File

@ -1,5 +1,5 @@
''' '''
Module for running arbitrairy tests Module for running arbitrary tests
''' '''
import time import time
@ -26,7 +26,7 @@ def ping():
def fib(long num): def fib(long num):
''' '''
Return a fibonachi sequence up to the passed number, and the time it took Return a Fibonacci sequence up to the passed number, and the time it took
to compute in seconds. Used for performance tests to compute in seconds. Used for performance tests
CLI Example: CLI Example:

View File

@ -10,7 +10,6 @@ data
import os import os
import grp import grp
import pwd import pwd
import hashlib
def gid_to_group(gid): def gid_to_group(gid):
''' '''
@ -135,7 +134,7 @@ def set_mode(path, mode):
def chown(path, user, group): def chown(path, user, group):
''' '''
Chown a file, pass the filem the desired user and group Chown a file, pass the file the desired user and group
CLI Example: CLI Example:
salt '*' file.chown /etc/passwd root root salt '*' file.chown /etc/passwd root root

View File

@ -6,12 +6,14 @@ import socket
from string import ascii_letters, digits from string import ascii_letters, digits
def _sanitize_host(host): def _sanitize_host(host):
return "".join([c for c in host[0:255] if c in (ascii_letters + digits + '.')]) return "".join([
c for c in host[0:255] if c in (ascii_letters + digits + '.')
])
def ping(host): def ping(host):
''' '''
Performs a ping to a host Performs a ping to a host
CLI Example: CLI Example:
salt '*' network.ping archlinux.org -c 4 salt '*' network.ping archlinux.org -c 4
''' '''
@ -25,7 +27,7 @@ def ping(host):
def netstat(): def netstat():
''' '''
Return information on open ports and states Return information on open ports and states
CLI Example: CLI Example:
salt '*' network.netstat salt '*' network.netstat
''' '''
@ -66,7 +68,7 @@ def netstat():
def traceroute(host): def traceroute(host):
''' '''
Performs a traceroute to a 3rd party host Performs a traceroute to a 3rd party host
CLI Example: CLI Example:
salt '*' network.traceroute archlinux.org salt '*' network.traceroute archlinux.org
''' '''
@ -98,7 +100,7 @@ def traceroute(host):
def dig(host): def dig(host):
''' '''
Performs a DNS lookup with dig Performs a DNS lookup with dig
CLI Example: CLI Example:
salt '*' network.dig archlinux.org salt '*' network.dig archlinux.org
''' '''
@ -112,7 +114,7 @@ def dig(host):
def isportopen(host, port): def isportopen(host, port):
''' '''
Return status of a port Return status of a port
CLI Example: CLI Example:
salt '*' network.isportopen 127.0.0.1 22 salt '*' network.isportopen 127.0.0.1 22
''' '''

View File

@ -153,13 +153,13 @@ def upgrade():
pkgs[npkg] = {'old': '', pkgs[npkg] = {'old': '',
'new': new[npkg]} 'new': new[npkg]}
return pkgs return pkgs
def remove(name): def remove(name):
''' '''
Remove a single package with pacman -R Remove a single package with pacman -R
Return a list containing the removed packages: Return a list containing the removed packages:
CLI Example: CLI Example:
salt '*' pkg.remove <package name> salt '*' pkg.remove <package name>
''' '''
@ -175,7 +175,7 @@ def purge(name):
with it, this will call a pacman -Rsc with it, this will call a pacman -Rsc
Return a list containing the removed packages: Return a list containing the removed packages:
CLI Example: CLI Example:
salt '*' pkg.purge <package name> salt '*' pkg.purge <package name>

View File

@ -38,7 +38,7 @@ def stop(name):
def status(name, sig=None): def status(name, sig=None):
''' '''
Return the status for a service, returns the PID or an empty string if the Return the status for a service, returns the PID or an empty string if the
service is running or not, pass a signiture to use to find the service via service is running or not, pass a signature to use to find the service via
ps ps
CLI Example: CLI Example:

View File

@ -1,8 +1,6 @@
''' '''
Control the state system on the minion Control the state system on the minion
''' '''
# Import Python modules
import os
# Import salt modules # Import salt modules
import salt.state import salt.state
@ -41,7 +39,7 @@ def template(tem):
''' '''
st_ = salt.state.State(__opts__) st_ = salt.state.State(__opts__)
return st_.call_template(tem) return st_.call_template(tem)
def template_str(tem): def template_str(tem):
''' '''
Execute the information stored in a template file on the minion Execute the information stored in a template file on the minion
@ -51,4 +49,4 @@ def template_str(tem):
''' '''
st_ = salt.state.State(__opts__) st_ = salt.state.State(__opts__)
return st_.call_template_str(tem) return st_.call_template_str(tem)

View File

@ -7,7 +7,7 @@ import subprocess
__opts__ = {} __opts__ = {}
def custom(): def custom():
''' '''
Return a custom composite of status data and info for this minon, Return a custom composite of status data and info for this minon,
based on the minion config file. An example config like might be: based on the minion config file. An example config like might be:
@ -19,7 +19,7 @@ def custom():
This function is meant to replace all_status(), which returns This function is meant to replace all_status(), which returns
anything and everything, which we probably don't want. anything and everything, which we probably don't want.
By default, nothing is returned. Warning: Depending on what you By default, nothing is returned. Warning: Depending on what you
include, there can be a LOT here! include, there can be a LOT here!
@ -38,7 +38,7 @@ def custom():
for item in __opts__[opt]: for item in __opts__[opt]:
ret[item] = vals[item] ret[item] = vals[item]
return ret return ret
def uptime(): def uptime():
''' '''
@ -59,7 +59,7 @@ def loadavg():
''' '''
comps = open('/proc/loadavg', 'r').read().strip() comps = open('/proc/loadavg', 'r').read().strip()
load_avg = comps.split() load_avg = comps.split()
return { return {
'1-min': load_avg[1], '1-min': load_avg[1],
'5-min': load_avg[2], '5-min': load_avg[2],
'15-min': load_avg[3], '15-min': load_avg[3],
@ -105,7 +105,7 @@ def cpustats():
def meminfo(): def meminfo():
''' '''
Return the CPU stats for this minon Return the CPU stats for this minion
CLI Example: CLI Example:
salt '*' status.meminfo salt '*' status.meminfo
@ -125,8 +125,8 @@ def meminfo():
return ret return ret
def cpuinfo(): def cpuinfo():
''' '''
Return the CPU info for this minon Return the CPU info for this minion
CLI Example: CLI Example:
salt '*' status.cpuinfo salt '*' status.cpuinfo
@ -142,11 +142,11 @@ def cpuinfo():
ret[comps[0]] = comps[1].split() ret[comps[0]] = comps[1].split()
else: else:
ret[comps[0]] = comps[1].strip() ret[comps[0]] = comps[1].strip()
return ret return ret
def diskstats(): def diskstats():
''' '''
Return the disk stats for this minon Return the disk stats for this minion
CLI Example: CLI Example:
salt '*' status.diskstats salt '*' status.diskstats
@ -177,7 +177,7 @@ def diskstats():
def vmstats(): def vmstats():
''' '''
Return the virtual memory stats for this minon Return the virtual memory stats for this minion
CLI Example: CLI Example:
salt '*' status.vmstats salt '*' status.vmstats
@ -192,8 +192,8 @@ def vmstats():
return ret return ret
def netstats(): def netstats():
''' '''
Return the network stats for this minon Return the network stats for this minion
CLI Example: CLI Example:
salt '*' status.netstats salt '*' status.netstats
@ -206,22 +206,22 @@ def netstats():
continue continue
comps = line.split() comps = line.split()
if comps[0] == headers[0]: if comps[0] == headers[0]:
index = len(headers) - 1 index = len(headers) - 1
row = {} row = {}
for field in range(index): for field in range(index):
if field < 1: if field < 1:
continue continue
else: else:
row[headers[field]] = comps[field] row[headers[field]] = comps[field]
rowname = headers[0].replace(':', '') rowname = headers[0].replace(':', '')
ret[rowname] = row ret[rowname] = row
else: else:
headers = comps headers = comps
return ret return ret
def netdev(): def netdev():
''' '''
Return the network device stats for this minon Return the network device stats for this minion
CLI Example: CLI Example:
salt '*' status.netdev salt '*' status.netdev
@ -256,8 +256,8 @@ def netdev():
return ret return ret
def w(): def w():
''' '''
Return a list of logged in users for this minon, using the w command Return a list of logged in users for this minion, using the w command
CLI Example: CLI Example:
salt '*' status.w salt '*' status.w
@ -270,7 +270,7 @@ def w():
if not row.count(' '): if not row.count(' '):
continue continue
comps = row.split() comps = row.split()
rec = { rec = {
'user': comps[0], 'user': comps[0],
'tty': comps[1], 'tty': comps[1],
'login': comps[2], 'login': comps[2],
@ -278,13 +278,14 @@ def w():
'jcpu': comps[4], 'jcpu': comps[4],
'pcpu': comps[5], 'pcpu': comps[5],
'what': ' '.join(comps[6:]), 'what': ' '.join(comps[6:]),
} }
user_list.append( rec ) user_list.append( rec )
return user_list return user_list
def all_status(): def all_status():
''' '''
Return a composite of all status data and info for this minon. Warning: There is a LOT here! Return a composite of all status data and info for this minoon.
Warning: There is a LOT here!
CLI Example: CLI Example:
salt '*' status.all_status salt '*' status.all_status

View File

@ -1,5 +1,5 @@
''' '''
Module for viewing and modifying sysctl paramters Module for viewing and modifying sysctl parameters
''' '''
import subprocess import subprocess

View File

@ -1,5 +1,5 @@
''' '''
Module for running arbitrairy tests Module for running arbitrary tests
''' '''
import time import time
@ -50,7 +50,7 @@ def get_opts():
def fib(num): def fib(num):
''' '''
Return a fibonachi sequence up to the passed number, and the time it took Return a Fibonacci sequence up to the passed number, and the time it took
to compute in seconds. Used for performance tests to compute in seconds. Used for performance tests
CLI Example: CLI Example:

View File

@ -1,5 +1,5 @@
''' '''
Work with vitual machines managed by libvirt Work with virtual machines managed by libvirt
''' '''
# Special Thanks to Michael Dehann, many of the concepts, and a few structures # Special Thanks to Michael Dehann, many of the concepts, and a few structures
# of his in the virt func module have been used # of his in the virt func module have been used
@ -39,7 +39,7 @@ def __get_conn():
def _get_dom(vm_): def _get_dom(vm_):
''' '''
Return a domain object for the named vm Return a domain object for the named vm
''' '''
conn = __get_conn() conn = __get_conn()
if not list_vms().count(vm_): if not list_vms().count(vm_):
@ -63,7 +63,7 @@ def _libvirt_creds():
def list_vms(): def list_vms():
''' '''
Return a list of virtual machine names on the minion Return a list of virtual machine names on the minion
CLI Example: CLI Example:
salt '*' virt.list_vms salt '*' virt.list_vms
''' '''
@ -109,7 +109,6 @@ def node_info():
salt '*' virt.node_info salt '*' virt.node_info
''' '''
conn = __get_conn() conn = __get_conn()
info = {}
raw = conn.getInfo() raw = conn.getInfo()
info = { info = {
'cpumodel' : str(raw[0]), 'cpumodel' : str(raw[0]),
@ -343,7 +342,7 @@ def migrate(vm_, target):
def seed_non_shared_migrate(disks, force=False): def seed_non_shared_migrate(disks, force=False):
''' '''
Non shared migration reqiuires that the disks be present on the migration Non shared migration requires that the disks be present on the migration
destination, pass the disks information via this function, to the destination, pass the disks information via this function, to the
migration destination before executing the migration. migration destination before executing the migration.
@ -355,7 +354,7 @@ def seed_non_shared_migrate(disks, force=False):
form = data['file format'] form = data['file format']
size = data['virtual size'].split()[1][1:] size = data['virtual size'].split()[1][1:]
if os.path.isfile(fn_) and not force: if os.path.isfile(fn_) and not force:
# the target exists, check to see if is is compatable # the target exists, check to see if is is compatible
pre = yaml.load(subprocess.Popen('qemu-img info arch', pre = yaml.load(subprocess.Popen('qemu-img info arch',
shell=True, shell=True,
stdout=subprocess.PIPE).communicate()[0]) stdout=subprocess.PIPE).communicate()[0])
@ -375,7 +374,7 @@ def seed_non_shared_migrate(disks, force=False):
def destroy(vm_): def destroy(vm_):
''' '''
Hard power down the virtual machine, this is equivelent to pulling the Hard power down the virtual machine, this is equivalent to pulling the
power power
CLI Example: CLI Example:
@ -405,7 +404,7 @@ def undefine(vm_):
def purge(vm_, dirs=False): def purge(vm_, dirs=False):
''' '''
Recursively destroy and delete a virtual machine, pass True for dirs to Recursively destroy and delete a virtual machine, pass True for dir's to
also delete the directories containing the virtual machine disk images - also delete the directories containing the virtual machine disk images -
USE WITH EXTREAME CAUTION! USE WITH EXTREAME CAUTION!
@ -426,7 +425,7 @@ def purge(vm_, dirs=False):
def virt_type(): def virt_type():
''' '''
Returns the virtual machine type as a string Returns the virtual machine type as a string
CLI Example: CLI Example:
salt '*' virt.virt_type salt '*' virt.virt_type
''' '''

View File

@ -14,7 +14,7 @@ def __virtual__():
def _list_removed(old, new): def _list_removed(old, new):
''' '''
List the pachages which have been removed between the two package objects List the packages which have been removed between the two package objects
''' '''
pkgs = [] pkgs = []
for pkg in old: for pkg in old:
@ -118,13 +118,13 @@ def upgrade():
pkgs[npkg] = {'old': '', pkgs[npkg] = {'old': '',
'new': new[npkg]} 'new': new[npkg]}
return pkgs return pkgs
def remove(pkg): def remove(pkg):
''' '''
Remove a single package with yum remove Remove a single package with yum remove
Return a list containing the removed packages: Return a list containing the removed packages:
CLI Example: CLI Example:
salt '*' pkg.remove <package name> salt '*' pkg.remove <package name>
''' '''
@ -139,7 +139,7 @@ def purge(pkg):
Yum does not have a purge, this function calls remove Yum does not have a purge, this function calls remove
Return a list containing the removed packages: Return a list containing the removed packages:
CLI Example: CLI Example:
salt '*' pkg.purge <package name> salt '*' pkg.purge <package name>

View File

@ -1,7 +1,7 @@
''' '''
Return data to a redis server Return data to a redis server
This is a VERY simple example for pushing data to a redis server and is not This is a VERY simple example for pushing data to a redis server and is not
nessisarily intended as a usable interface. necessarily intended as a usable interface.
''' '''
import redis import redis
@ -21,7 +21,7 @@ def returner(ret):
host=__opts__['redis.host'], host=__opts__['redis.host'],
port=__opts__['redis.port'], port=__opts__['redis.port'],
db=__opts__['redis.db']) db=__opts__['redis.db'])
serv.sadd(ret['id'] + ':' + 'jobs', ret['jid']) serv.sadd("%(id)s:jobs" % ret, ret['jid'])
serv.set(ret['jid'] + ':' + ret['id'], json.dumps(ret['return'])) serv.set("%(jid)s:%(id)s" % ret, json.dumps(ret['return']))
serv.sadd('jobs', ret['jid']) serv.sadd('jobs', ret['jid'])
serv.sadd(ret['jid'], ret['id']) serv.sadd(ret['jid'], ret['id'])

View File

@ -1,6 +1,6 @@
''' '''
The module used to execute states in salt. A state is unlike a module execution The module used to execute states in salt. A state is unlike a module execution
in that instead of just executing a command it ensure that a certian state is in that instead of just executing a command it ensure that a certain state is
present on the system. present on the system.
The data sent to the state calls is as follows: The data sent to the state calls is as follows:
@ -15,6 +15,7 @@ import sys
import os import os
import copy import copy
import inspect import inspect
import tempfile
# Import Salt modules # Import Salt modules
import salt.loader import salt.loader
@ -71,7 +72,7 @@ class State(object):
def format_call(self, data): def format_call(self, data):
''' '''
Formats low data into a list of dicts used to acctually call the state, Formats low data into a list of dict's used to actually call the state,
returns: returns:
{ {
'full': 'module.function', 'full': 'module.function',
@ -110,7 +111,7 @@ class State(object):
def compile_high_data(self, high): def compile_high_data(self, high):
''' '''
"Compile" the high data as it is retireved from the cli or yaml into "Compile" the high data as it is retrieved from the cli or yaml into
the individual state executor structures the individual state executor structures
''' '''
chunks = [] chunks = []
@ -148,8 +149,8 @@ class State(object):
def compile_template(self, template): def compile_template(self, template):
''' '''
Take the path to a template and return the high data structure derived from the Take the path to a template and return the high data structure derived
template. from the template.
''' '''
if not os.path.isfile(template): if not os.path.isfile(template):
return {} return {}
@ -157,8 +158,8 @@ class State(object):
def compile_template_str(self, template): def compile_template_str(self, template):
''' '''
Take the path to a template and return the high data structure derived from the Take the path to a template and return the high data structure derived
template. from the template.
''' '''
fn_ = tempfile.mkstemp()[1] fn_ = tempfile.mkstemp()[1]
open(fn_, 'w+').write(template) open(fn_, 'w+').write(template)
@ -168,7 +169,8 @@ class State(object):
def call(self, data): def call(self, data):
''' '''
Call a state directly with the low data structure, verify data before processing Call a state directly with the low data structure, verify data before
processing.
''' '''
ret = {'changes': None, ret = {'changes': None,
'result': False, 'result': False,
@ -178,7 +180,7 @@ class State(object):
def call_chunks(self, chunks): def call_chunks(self, chunks):
''' '''
Itterate over a list of chunks and call them, checking for requires. Iterate over a list of chunks and call them, checking for requires.
''' '''
running = {} running = {}
for low in chunks: for low in chunks:

View File

@ -37,7 +37,7 @@ def run(name,
return ret return ret
if unless: if unless:
if __salt__['cmd.retcode'](unless) == 0: if __salt__['cmd.retcode'](unless) == 0:
ret['comment'] = 'unless executed sucsessfully' ret['comment'] = 'unless executed successfully'
ret['result'] = True ret['result'] = True
return ret return ret
if not os.path.isdir(cwd): if not os.path.isdir(cwd):

View File

@ -3,7 +3,6 @@ Manage file states
''' '''
import os import os
import hashlib
import shutil import shutil
import tempfile import tempfile
import difflib import difflib
@ -170,7 +169,7 @@ def managed(name,
'changes': changes, 'changes': changes,
'result': False, 'result': False,
'comment': 'Source file ' + source + ' not found'} 'comment': 'Source file ' + source + ' not found'}
# Handle any template management that is neded # Handle any template management that is needed
if template: if template:
t_key = '_' + template t_key = '_' + template
if locals().has_key(t_key): if locals().has_key(t_key):

View File

@ -30,34 +30,34 @@ def daemonize():
''' '''
Daemonize a process Daemonize a process
''' '''
try: try:
pid = os.fork() pid = os.fork()
if pid > 0: if pid > 0:
# exit first parent # exit first parent
sys.exit(0) sys.exit(0)
except OSError, e: except OSError, e:
print >> sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror) print >> sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
sys.exit(1) sys.exit(1)
# decouple from parent environment # decouple from parent environment
os.chdir("/") os.chdir("/")
os.setsid() os.setsid()
os.umask(022) os.umask(022)
# do second fork # do second fork
try: try:
pid = os.fork() pid = os.fork()
if pid > 0: if pid > 0:
# print "Daemon PID %d" % pid # print "Daemon PID %d" % pid
sys.exit(0) sys.exit(0)
except OSError, e: except OSError, e:
print >> sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror) print >> sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror)
sys.exit(1) sys.exit(1)
dev_null = open('/dev/null','rw') dev_null = open('/dev/null','rw')
os.dup2(dev_null.fileno(), sys.stdin.fileno()) os.dup2(dev_null.fileno(), sys.stdin.fileno())
os.dup2(dev_null.fileno(), sys.stdout.fileno()) os.dup2(dev_null.fileno(), sys.stdout.fileno())
os.dup2(dev_null.fileno(), sys.stderr.fileno()) os.dup2(dev_null.fileno(), sys.stderr.fileno())
def check_root(): def check_root():
''' '''
@ -65,9 +65,9 @@ def check_root():
verify that root is the user before the application discovers it. verify that root is the user before the application discovers it.
''' '''
if os.getuid(): if os.getuid():
print 'Sorry, the salt must run as root, it needs to opperate'\ print ('Sorry, the salt must run as root, it needs to operate '
+ ' in a privileged environment to do what it does.\n' \ 'in a privileged environment to do what it does.\n'
+ 'http://xkcd.com/838/' 'http://xkcd.com/838/')
sys.exit(1) sys.exit(1)

View File

@ -2,8 +2,8 @@
''' '''
Publish commands to the salt system from the command line on the master. Publish commands to the salt system from the command line on the master.
''' '''
# Eventually we need to be able to interlink salt masters and form quorums, # Eventually we need to be able to interlink salt masters and form quorum's,
# and create the ability for externel systesm to talk to salt. This interface # and create the ability for external systems to talk to salt. This interface
# is just a cli interface so that we can get this kicked off and working # is just a cli interface so that we can get this kicked off and working
import salt.cli import salt.cli

View File

@ -2,8 +2,8 @@
''' '''
Publish commands to the salt system from the command line on the master. Publish commands to the salt system from the command line on the master.
''' '''
# Eventually we need to be able to interlink salt masters and form quorums, # Eventually we need to be able to interlink salt masters and form quorum's,
# and create the ability for externel systesm to talk to salt. This interface # and create the ability for external systems to talk to salt. This interface
# is just a cli interface so that we can get this kicked off and working # is just a cli interface so that we can get this kicked off and working
import salt.cli import salt.cli