%PDF- %PDF-
Direktori : /usr/lib/python2.7/site-packages/salt/modules/ |
Current File : //usr/lib/python2.7/site-packages/salt/modules/defaults.py |
# -*- coding: utf-8 -*- ''' Module to work with salt formula defaults files ''' from __future__ import absolute_import, print_function, unicode_literals import copy import logging import os import salt.fileclient import salt.utils.data import salt.utils.dictupdate as dictupdate import salt.utils.files import salt.utils.json import salt.utils.url import salt.utils.yaml __virtualname__ = 'defaults' log = logging.getLogger(__name__) def _mk_client(): ''' Create a file client and add it to the context ''' if 'cp.fileclient' not in __context__: __context__['cp.fileclient'] = \ salt.fileclient.get_file_client(__opts__) def _load(formula): ''' Generates a list of salt://<formula>/defaults.(json|yaml) files and fetches them from the Salt master. Returns first defaults file as python dict. ''' # Compute possibilities _mk_client() paths = [] for ext in ('yaml', 'json'): source_url = salt.utils.url.create(formula + '/defaults.' + ext) paths.append(source_url) # Fetch files from master defaults_files = __context__['cp.fileclient'].cache_files(paths) for file_ in defaults_files: if not file_: # Skip empty string returned by cp.fileclient.cache_files. continue suffix = file_.rsplit('.', 1)[-1] if suffix == 'yaml': loader = salt.utils.yaml.safe_load elif suffix == 'json': loader = salt.utils.json.load else: log.debug("Failed to determine loader for %r", file_) continue if os.path.exists(file_): log.debug("Reading defaults from %r", file_) with salt.utils.files.fopen(file_) as fhr: defaults = loader(fhr) log.debug("Read defaults %r", defaults) return defaults or {} def get(key, default=''): ''' defaults.get is used much like pillar.get except that it will read a default value for a pillar from defaults.json or defaults.yaml files that are stored in the root of a salt formula. CLI Example: .. code-block:: bash salt '*' defaults.get core:users:root The defaults is computed from pillar key. The first entry is considered as the formula namespace. For example, querying ``core:users:root`` will try to load ``salt://core/defaults.yaml`` and ``salt://core/defaults.json``. ''' # Determine formula namespace from query if ':' in key: namespace, key = key.split(':', 1) else: namespace, key = key, None # Fetch and load defaults formula files from states. defaults = _load(namespace) # Fetch value if key: return salt.utils.data.traverse_dict_and_list(defaults, key, default) else: return defaults def merge(dest, src, merge_lists=False, in_place=True): ''' defaults.merge Allows deep merging of dicts in formulas. merge_lists : False If True, it will also merge lists instead of replace their items. in_place : True If True, it will merge into dest dict, if not it will make a new copy from that dict and return it. CLI Example: .. code-block:: bash salt '*' default.merge a=b d=e It is more typical to use this in a templating language in formulas, instead of directly on the command-line. ''' if in_place: merged = dest else: merged = copy.deepcopy(dest) return dictupdate.update(merged, src, merge_lists=merge_lists) def deepcopy(source): ''' defaults.deepcopy Allows deep copy of objects in formulas. By default, Python does not copy objects, it creates bindings between a target and an object. It is more typical to use this in a templating language in formulas, instead of directly on the command-line. ''' return copy.deepcopy(source) def update(dest, defaults, merge_lists=True, in_place=True): ''' defaults.update Allows to set defaults for group of data set e.g. group for nodes. This function is a combination of defaults.merge and defaults.deepcopy to avoid redundant in jinja. Example: .. code-block:: yaml group01: defaults: enabled: True extra: - test - stage nodes: host01: index: foo upstream: bar host02: index: foo2 upstream: bar2 .. code-block:: jinja {% do salt['defaults.update'](group01.nodes, group01.defaults) %} Each node will look like the following: .. code-block:: yaml host01: enabled: True index: foo upstream: bar extra: - test - stage merge_lists : True If True, it will also merge lists instead of replace their items. in_place : True If True, it will merge into dest dict. if not it will make a new copy from that dict and return it. It is more typical to use this in a templating language in formulas, instead of directly on the command-line. ''' if in_place: nodes = dest else: nodes = deepcopy(dest) for node_name, node_vars in nodes.items(): defaults_vars = deepcopy(defaults) node_vars = merge(defaults_vars, node_vars, merge_lists=merge_lists) nodes[node_name] = node_vars return nodes