Merge remote branch 'upstream/develop' into debpackages

This commit is contained in:
Corey Quinn 2011-12-27 06:59:08 -08:00
commit 60e75873db
20 changed files with 232 additions and 82 deletions

View File

@ -226,6 +226,11 @@ def os_data():
Return grains pertaining to the operating system
'''
grains = {}
if 'os' in os.environ:
if os.environ['os'].startswith('Windows'):
grains['os'] = 'Windows'
grains['kernel'] = 'Windows'
return grains
grains.update(_kernel())
if grains['kernel'] == 'Linux':

View File

@ -205,7 +205,7 @@ class Loader(object):
log.info('Cython is enabled in options put not present '
'on the system path. Skipping Cython modules.')
for mod_dir in self.module_dirs:
if not mod_dir.startswith('/'):
if not os.path.isabs(mod_dir):
continue
if not os.path.isdir(mod_dir):
continue
@ -240,7 +240,7 @@ class Loader(object):
mod.__grains__ = self.grains
if pack:
if type(pack) == type(list()):
if isinstance(pack, list):
for chunk in pack:
setattr(mod, chunk['name'], chunk['value'])
else:
@ -349,14 +349,14 @@ class Loader(object):
if not key[key.index('.') + 1:] == 'core':
continue
ret = fun()
if not type(ret) == type(dict()):
if not isinstance(ret, dict):
continue
grains.update(ret)
for key, fun in funcs.items():
if key[key.index('.') + 1:] == 'core':
continue
ret = fun()
if not type(ret) == type(dict()):
if not isinstance(ret, dict):
continue
grains.update(ret)
return grains

View File

@ -4,25 +4,25 @@ involves preparing the three listeners and the workers needed by the master.
'''
# Import python modules
import datetime
import hashlib
import logging
import multiprocessing
import os
import re
import shutil
import tempfile
import time
import shutil
import logging
import hashlib
import tempfile
import datetime
import multiprocessing
# Import zeromq
from M2Crypto import RSA
import zmq
from M2Crypto import RSA
# Import salt modules
import salt.client
import salt.crypt
import salt.payload
import salt.utils
import salt.client
import salt.payload
log = logging.getLogger(__name__)
@ -106,7 +106,10 @@ class Master(SMaster):
for jid in os.listdir(jid_root):
if int(cur) - int(jid[:10]) > self.opts['keep_jobs']:
shutil.rmtree(os.path.join(jid_root, jid))
time.sleep(60)
try:
time.sleep(60)
except KeyboardInterrupt:
break
def start(self):
'''
@ -128,7 +131,13 @@ class Master(SMaster):
aes_funcs,
clear_funcs)
reqserv.start_publisher()
reqserv.run()
try:
reqserv.run()
except KeyboardInterrupt:
# Shut the master down gracefully on SIGINT
log.warn('Stopping the Salt Master')
raise SystemExit('\nExiting on Ctrl-c')
class Publisher(multiprocessing.Process):
@ -137,7 +146,7 @@ class Publisher(multiprocessing.Process):
commands.
'''
def __init__(self, opts):
multiprocessing.Process.__init__(self)
super(Publisher, self).__init__()
self.opts = opts
def run(self):
@ -155,10 +164,14 @@ class Publisher(multiprocessing.Process):
pub_sock.bind(pub_uri)
pull_sock.bind(pull_uri)
while True:
package = pull_sock.recv()
log.info('Publishing command')
pub_sock.send(package)
try:
while True:
package = pull_sock.recv()
log.info('Publishing command')
pub_sock.send(package)
except KeyboardInterrupt:
pub_sock.close()
pull_sock.close()
class ReqServer(object):
@ -247,13 +260,16 @@ class MWorker(multiprocessing.Process):
os.path.join(self.opts['sock_dir'], 'workers.ipc')
)
log.info('Worker binding to socket {0}'.format(w_uri))
socket.connect(w_uri)
try:
socket.connect(w_uri)
while True:
package = socket.recv()
payload = self.serial.loads(package)
ret = self.serial.dumps(self._handle_payload(payload))
socket.send(ret)
while True:
package = socket.recv()
payload = self.serial.loads(package)
ret = self.serial.dumps(self._handle_payload(payload))
socket.send(ret)
except KeyboardInterrupt:
socket.close()
def _handle_payload(self, payload):
'''

View File

@ -8,6 +8,7 @@ import contextlib
import glob
import logging
import multiprocessing
import hashlib
import os
import re
import shutil
@ -166,7 +167,7 @@ class Minion(object):
self.functions, self.returners = self.__load_modules()
if self.opts['multiprocessing']:
if type(data['fun']) == type(list()):
if isinstance(data['fun'], list):
multiprocessing.Process(
target=lambda: self._thread_multi_return(data)
).start()
@ -175,7 +176,7 @@ class Minion(object):
target=lambda: self._thread_return(data)
).start()
else:
if type(data['fun']) == type(list()):
if isinstance(data['fun'], list):
threading.Thread(
target=lambda: self._thread_multi_return(data)
).start()
@ -473,7 +474,7 @@ class Matcher(object):
'''
matcher = 'glob'
for item in data:
if type(item) == type(dict()):
if isinstance(item, dict):
if 'match' in item:
matcher = item['match']
if hasattr(self, matcher + '_match'):
@ -631,6 +632,19 @@ class FileClient(object):
self.socket.send(self.serial.dumps(payload))
data = self.auth.crypticle.loads(self.serial.loads(self.socket.recv()))
if not data['data']:
if not fn_ and data['dest']:
# This is a 0 byte file on the master
dest = os.path.join(
self.opts['cachedir'],
'files',
env,
data['dest']
)
destdir = os.path.dirname(dest)
if not os.path.isdir(destdir):
os.makedirs(destdir)
if not os.path.exists(dest):
open(dest, 'w+').write(data['data'])
break
if not fn_:
dest = os.path.join(
@ -726,7 +740,19 @@ class FileClient(object):
salt master file server prepend the path with salt://<file on server>
otherwise, prepend the file with / for a local file.
'''
path = self._check_proto(path)
try:
path = self._check_proto(path)
except MinionError:
if not os.path.isfile(path):
err = ('Specified file {0} is not present to generate '
'hash').format(path)
log.warning(err)
return {}
else:
ret = {}
ret['hsum'] = hashlib.md5(open(path, 'rb').read()).hexdigest()
ret['hash_type'] = 'md5'
return ret
payload = {'enc': 'aes'}
load = {'path': path,
'env': env,

View File

@ -113,7 +113,7 @@ def set_fstab(
salt '*' mount.set_fstab /mnt/foo /dev/sdz1 ext4
'''
# Fix the opts type if it is a list
if type(opts) == type(list()):
if isinstance(opts, list):
opts = ','.join(opts)
lines = []
change = False
@ -189,7 +189,7 @@ def mount(name, device, mkmnt=False, fstype='', opts='defaults'):
salt '*' mount.mount /mnt/foo /dev/sdz1 True
'''
if type(opts) == type(str()):
if isinstance(opts, basestring):
opts = opts.split(',')
if not os.path.exists(name) and mkmnt:
os.makedirs(name)
@ -212,7 +212,7 @@ def remount(name, device, mkmnt=False, fstype='', opts='defaults'):
salt '*' mount.remount /mnt/foo /dev/sdz1 True
'''
if type(opts) == type(str()):
if isinstance(opts, basestring):
opts = opts.split(',')
mnts = active()
if name in mnts:

View File

@ -27,7 +27,7 @@ def add(name,
salt '*' user.add name <uid> <gid> <groups> <home> <shell>
'''
if type(groups) == type(str()):
if isinstance(groups, basestring):
groups = groups.split(',')
cmd = 'pw useradd -s {0} '.format(shell)
if uid:
@ -169,7 +169,7 @@ def chgroups(name, groups, append=False):
salt '*' user.chgroups foo wheel,root True
'''
if type(groups) == type(str()):
if isinstance(groups, basestring):
groups = groups.split(',')
ugrps = set(list_groups(name))
if ugrps == set(groups):

View File

@ -112,10 +112,10 @@ def _get_none_or_value(value):
'''
if value is None:
return None
elif value:
elif not value:
return value
# if it's a string, and it's not empty check for none
elif type(value) == str:
elif isinstance(value, basestring):
if value.lower() == 'none':
return None
return value
@ -333,11 +333,11 @@ def _merge_options(options):
{option:boolean}
'''
defaults = __opts__['solr.dih.import_options']
if type(options) == dict:
if isinstance(options, dict):
defaults.update(options)
for (k,v) in defaults.items():
if type(v) is bool:
defaults[k] = str(bool(v)).lower()
defaults[k] = str(v).lower()
return defaults
def _pre_index_check(handler, host=None, core_name=None):
@ -415,11 +415,11 @@ def _find_value(ret_dict, key, path=None):
for (k, v) in ret_dict.items():
if k == key:
ret.append({path:v})
if type(v) is list:
if isinstance(v, list):
for x in v:
if type(x) is dict:
if isinstance(x, dict):
ret = ret + _find_value(x, key, path)
if type(v) is dict:
if isinstance(v, dict):
ret = ret + _find_value(v, key, path)
return ret

View File

@ -26,7 +26,7 @@ def add(name,
salt '*' user.add name <uid> <gid> <groups> <home> <shell>
'''
if type(groups) == type(str()):
if isinstance(groups, basestring):
groups = groups.split(',')
cmd = 'useradd -s {0} '.format(shell)
if uid:
@ -170,7 +170,7 @@ def chgroups(name, groups, append=False):
salt '*' user.chgroups foo wheel,root True
'''
if type(groups) == type(str()):
if isinstance(groups, basestring):
groups = groups.split(',')
ugrps = set(list_groups(name))
if ugrps == set(groups):

View File

@ -7,16 +7,13 @@ high data format for salt states.
import json
import os
from salt.utils.jinja import get_template
# Import Third Party libs
from jinja2 import Template
def render(template, env='', sls=''):
def render(template_file, env='', sls=''):
'''
Render the data passing the functions and grains into the rendering system
'''
if not os.path.isfile(template):
if not os.path.isfile(template_file):
return {}
passthrough = {}
@ -25,7 +22,8 @@ def render(template, env='', sls=''):
passthrough['env'] = env
passthrough['sls'] = sls
template = Template(open(template, 'r').read())
template = get_template(template_file, __opts__, env)
json_data = template.render(**passthrough)
return json.loads(json_data)

View File

@ -6,17 +6,14 @@ high data format for salt states.
'''
import os
# Import Third Party libs
from jinja2 import Template
import yaml
from salt.utils.jinja import get_template
def render(template, env='', sls=''):
def render(template_file, env='', sls=''):
'''
Render the data passing the functions and grains into the rendering system
'''
if not os.path.isfile(template):
if not os.path.isfile(template_file):
return {}
passthrough = {}
@ -25,7 +22,8 @@ def render(template, env='', sls=''):
passthrough['env'] = env
passthrough['sls'] = sls
template = Template(open(template, 'r').read())
template = get_template(template_file, __opts__, env)
yaml_data = template.render(**passthrough)
return yaml.safe_load(yaml_data)

View File

@ -34,7 +34,7 @@ def returner(ret):
col = db[ret['id']]
back = {}
if type(ret['return']) == type(dict()):
if isinstance(ret['return'], dict):
for key in ret['return']:
back[key.replace('.', '-')] = ret['return'][key]
else:

View File

@ -29,19 +29,19 @@ def format_log(ret):
Format the state into a log message
'''
msg = ''
if type(ret) == type(dict()):
if isinstance(ret, dict):
# Looks like the ret may be a valid state return
if 'changes' in ret:
# Yep, looks like a valid state return
chg = ret['changes']
if not chg:
msg = 'No changes made for {0[name]}'.format(ret)
elif type(chg) == type(dict()):
elif isinstance(chg, dict):
if 'diff' in chg:
if type(chg['diff']) == type(str()):
if isinstance(chg['diff'], basestring):
msg = 'File changed:\n{0}'.format(
chg['diff'])
if type(chg[chg.keys()[0]]) == type(dict()):
if isinstance(chg[chg.keys()[0]], dict):
if 'new' in chg[chg.keys()[0]]:
# This is the return data from a package install
msg = 'Installed Packages:\n'
@ -319,9 +319,9 @@ class State(object):
aspec = inspect.getargspec(self.states[ret['full']])
arglen = 0
deflen = 0
if type(aspec[0]) == type(list()):
if isinstance(aspec[0], list):
arglen = len(aspec[0])
if type(aspec[3]) == type(tuple()):
if isinstance(aspec[3], tuple):
deflen = len(aspec[3])
kwargs = {}
for ind in range(arglen - 1, 0, -1):
@ -360,10 +360,10 @@ class State(object):
funcs = set()
names = set()
for arg in run:
if type(arg) == type(str()):
if isinstance(arg, str):
funcs.add(arg)
continue
if type(arg) == type(dict()):
if isinstance(arg, dict):
for key, val in arg.items():
if key == 'names':
names.update(val)
@ -847,7 +847,7 @@ class HighState(object):
if env not in matches:
matches[env] = []
for item in data:
if type(item) == type(str()):
if isinstance(item, basestring):
matches[env].append(item)
return matches

View File

@ -21,6 +21,11 @@ makes use of the jinja templating system would look like this:
- group: root
- mode: 644
- template: jinja
- context:
custom_var: "override"
- defaults:
custom_var: "default value"
other_var: 123
Directories can be managed via the ``directory`` function. This function can
create and enforce the permissions on a directory. A directory statement will
@ -138,7 +143,7 @@ def _clean_dir(root, keep):
return list(removed)
def _mako(sfn, name, source, user, group, mode, env):
def _mako(sfn, name, source, user, group, mode, env, context=None):
'''
Render a mako template, returns the location of the rendered file,
return False if render fails.
@ -154,7 +159,7 @@ def _mako(sfn, name, source, user, group, mode, env):
'data': 'Failed to import jinja'}
try:
tgt = tempfile.mkstemp()[1]
passthrough = {}
passthrough = context if context else {}
passthrough.update(__salt__)
passthrough.update(__grains__)
template = Template(open(sfn, 'r').read())
@ -167,7 +172,7 @@ def _mako(sfn, name, source, user, group, mode, env):
'data': trb}
def _jinja(sfn, name, source, user, group, mode, env):
def _jinja(sfn, name, source, user, group, mode, env, context=None):
'''
Render a jinja2 template, returns the location of the rendered file,
return False if render fails.
@ -177,13 +182,13 @@ def _jinja(sfn, name, source, user, group, mode, env):
'data': <Error data or rendered file path>}
'''
try:
from jinja2 import Template
from salt.utils.jinja import get_template
except ImportError:
return {'result': False,
'data': 'Failed to import jinja'}
try:
tgt = tempfile.mkstemp()[1]
passthrough = {}
passthrough = context if context else {}
passthrough['salt'] = __salt__
passthrough['grains'] = __grains__
passthrough['name'] = name
@ -192,7 +197,7 @@ def _jinja(sfn, name, source, user, group, mode, env):
passthrough['group'] = group
passthrough['mode'] = mode
passthrough['env'] = env
template = Template(open(sfn, 'r').read())
template = get_template(sfn, __opts__, env)
open(tgt, 'w+').write(template.render(**passthrough))
return {'result': True,
'data': tgt}
@ -311,6 +316,8 @@ def managed(name,
mode=None,
template=None,
makedirs=False,
context=None,
defaults=None,
__env__='base'):
'''
Manage a given file, this function allows for a file to be downloaded from
@ -346,6 +353,12 @@ def managed(name,
the state will fail. If makedirs is set to True, then the parent
directories will be created to facilitate the creation of the named
file.
context
Overrides default context variables passed to the template.
defaults
Default context passed to the template.
'''
if mode:
mode = str(mode)
@ -360,6 +373,8 @@ def managed(name,
sfn = __salt__['cp.cache_file'](source, __env__)
t_key = '_{0}'.format(template)
if t_key in globals():
context_dict = defaults if defaults else {}
if context: context_dict.update(context)
data = globals()[t_key](
sfn,
name,
@ -367,7 +382,8 @@ def managed(name,
user,
group,
mode,
__env__
__env__,
context_dict
)
else:
ret['result'] = False

View File

@ -71,7 +71,7 @@ def mounted(
# Make sure that opts is correct, it can be a list or a comma delimited
# string
if type(opts) == type(str()):
if isinstance(opts, basestring):
opts = opts.split(',')
# Get the active data
@ -79,7 +79,7 @@ def mounted(
if name not in active:
# The mount is not present! Mount it
out = __salt__['mount.mount'](name, device, mkmnt, fstype, opts)
if type(out) == type(str()):
if isinstance(out, basestring):
# Failed to remount, the state has failed!
ret['comment'] = out
ret['result'] = False

76
salt/utils/jinja.py Normal file
View File

@ -0,0 +1,76 @@
from os import path
from jinja2 import Template, BaseLoader, Environment
from jinja2.loaders import split_template_path
from jinja2.exceptions import TemplateNotFound
import salt
def get_template(filename, opts, env):
loader = SaltCacheLoader(opts, env)
if filename.startswith(loader.searchpath):
jinja = Environment(loader=loader)
relpath = path.relpath(filename, loader.searchpath)
# the template was already fetched
loader.cached.append(relpath)
return jinja.get_template(relpath)
else:
# fallback for templates outside the state tree
return Template(open(filename, 'r').read())
class SaltCacheLoader(BaseLoader):
'''
A special jinja Template Loader for salt.
Requested templates are always fetched from the server
to guarantee that the file is up to date.
Templates are cached like regular salt states
and only loaded once per loader instance.
'''
def __init__(self, opts, env='base', encoding='utf-8'):
self.opts = opts
self.env = env
self.encoding = encoding
self.searchpath = path.join(opts['cachedir'], 'files', env)
self._file_client = None
self.cached = []
def file_client(self):
'''
Return a file client. Instantiates on first call.
'''
if not self._file_client:
self._file_client = salt.minion.FileClient(self.opts)
return self._file_client
def cache_file(self, template):
'''
Cache a file from the salt master
'''
saltpath = path.join('salt://', template)
self.file_client().get_file(saltpath, '', True, self.env)
def check_cache(self, template):
'''
Cache a file only once
'''
if template not in self.cached:
self.cache_file(template)
self.cached.append(template)
def get_source(self, environment, template):
# checks for relative '..' paths
template = path.join(*split_template_path(template))
self.check_cache(template)
filepath = path.join(self.searchpath, template)
try:
f = open(filepath, 'rb')
contents = f.read().decode(self.encoding)
except IOError:
raise TemplateNotFound(template)
finally:
f.close()
mtime = path.getmtime(filepath)
def uptodate():
try:
return path.getmtime(filepath) == mtime
except OSError:
return False
return contents, filepath, uptodate

View File

@ -14,4 +14,7 @@ def main():
client.run()
if __name__ == '__main__':
main()
try:
main()
except KeyboardInterrupt:
raise SystemExit('\nExiting gracefully on Ctrl-c')

View File

@ -15,4 +15,7 @@ def main():
client.run()
if __name__ == '__main__':
main()
try:
main()
except KeyboardInterrupt:
raise SystemExit('\nExiting gracefully on Ctrl-c')

View File

@ -14,4 +14,7 @@ def main():
cp_.run()
if __name__ == '__main__':
main()
try:
main()
except KeyboardInterrupt:
raise SystemExit('\nExiting gracefully on Ctrl-c')

View File

@ -14,4 +14,7 @@ def main():
saltkey.run()
if __name__ == '__main__':
main()
try:
main()
except KeyboardInterrupt:
raise SystemExit('\nExiting gracefully on Ctrl-c')

View File

@ -14,4 +14,7 @@ def main():
client.run()
if __name__ == '__main__':
main()
try:
main()
except KeyboardInterrupt:
raise SystemExit('\nExiting gracefully on Ctrl-c')