def gen_ini(self): yield '\n[{0}]\n'.format(self.name) sections_dict = OrderedDict() for name, value in self.iteritems(): if com_regx.match(name): yield '{0}\n'.format(value) elif isinstance(value, _Section): sections_dict.update({name: value}) else: yield '{0} {1} {2}\n'.format(name, self.sep, value) for name, value in sections_dict.iteritems(): for line in value.gen_ini(): yield line
def gen_ini(self): yield "{0}[{1}]{0}".format(os.linesep, self.name) sections_dict = OrderedDict() for name, value in six.iteritems(self): if com_regx.match(name): yield "{0}{1}".format(value, os.linesep) elif isinstance(value, _Section): sections_dict.update({name: value}) else: yield "{0}{1}{2}{3}".format( name, (" {0} ".format(self.sep) if self.sep != " " else self.sep), value, os.linesep ) for name, value in six.iteritems(sections_dict): for line in value.gen_ini(): yield line
def _uncomment_if_commented(self, opt_key): # should be called only if opt_key is not already present # will uncomment the key if commented and create a place holder # for the key where the correct value can be update later # used to preserve the ordering of comments and commented options # and to make sure options without sectons go above any section options_backup = OrderedDict() comment_index = None for key, value in self.iteritems(): if comment_index is not None: options_backup.update({key: value}) continue if '#comment' not in key: continue opt_match = opt_regx.match(value.lstrip('#')) if opt_match and opt_match.group(2) == opt_key: comment_index = key for key in options_backup: self.pop(key) self.pop(comment_index, None) super(_Section, self).update({opt_key: None}) for key, value in options_backup.iteritems(): super(_Section, self).update({key: value})
def serialize(cls, id_=None): # The order matters serialized = OrderedDict() if id_ is not None: # This is meant as a configuration section, sub json schema serialized['id'] = '{0}/{1}.json#'.format(BASE_SCHEMA_URL, id_) else: # Main configuration block, json schema serialized['$schema'] = 'http://json-schema.org/draft-04/schema#' if cls.title is not None: serialized['title'] = cls.title if cls.description is not None: if cls.description == cls.__doc__: serialized['description'] = textwrap.dedent(cls.description).strip() else: serialized['description'] = cls.description required = [] ordering = [] serialized['type'] = 'object' properties = OrderedDict() cls.after_items_update = [] for name in cls._order: skip_order = False if name in cls._sections: # pylint: disable=E1135 section = cls._sections[name] serialized_section = section.serialize(None if section.__flatten__ is True else name) if section.__flatten__ is True: # Flatten the configuration section into the parent # configuration properties.update(serialized_section['properties']) if 'x-ordering' in serialized_section: ordering.extend(serialized_section['x-ordering']) if 'required' in serialized_section: required.extend(serialized_section['required']) if hasattr(section, 'after_items_update'): cls.after_items_update.extend(section.after_items_update) skip_order = True else: # Store it as a configuration section properties[name] = serialized_section if name in cls._items: # pylint: disable=E1135 config = cls._items[name] # Handle the configuration items defined in the class instance if config.__flatten__ is True: serialized_config = config.serialize() cls.after_items_update.append(serialized_config) skip_order = True else: properties[name] = config.serialize() if config.required: # If it's a required item, add it to the required list required.append(name) if skip_order is False: # Store the order of the item if name not in ordering: ordering.append(name) if properties: serialized['properties'] = properties # Update the serialized object with any items to include after properties if cls.after_items_update: after_items_update = {} for entry in cls.after_items_update: name, data = next(six.iteritems(entry)) if name in after_items_update: after_items_update[name].extend(data) else: after_items_update[name] = data serialized.update(after_items_update) if required: # Only include required if not empty serialized['required'] = required if ordering: # Only include ordering if not empty serialized['x-ordering'] = ordering serialized['additionalProperties'] = cls.__allow_additional_items__ return serialized
def iostat(zpool=None, sample_time=5, parsable=True): ''' Display I/O statistics for the given pools zpool : string optional name of storage pool sample_time : int seconds to capture data before output default a sample of 5 seconds is used parsable : boolean display data in pythonc values (True, False, Bytes,...) .. versionadded:: 2016.3.0 .. versionchanged:: Fluorine Added ```parsable``` parameter that defaults to True CLI Example: .. code-block:: bash salt '*' zpool.iostat myzpool ''' ret = OrderedDict() ## get iostat output res = __salt__['cmd.run_all']( __utils__['zfs.zpool_command'](command='iostat', flags=['-v'], target=[zpool, sample_time, 2]), python_shell=False, ) if res['retcode'] != 0: return __utils__['zfs.parse_command_result'](res) # NOTE: command output for reference # ===================================================================== # capacity operations bandwidth # pool alloc free read write read write # ------------------------- ----- ----- ----- ----- ----- ----- # mypool 648G 1.18T 10 6 1.30M 817K # mirror 648G 1.18T 10 6 1.30M 817K # c0tXXXXCXXXXXXXXXXXd0 - - 9 5 1.29M 817K # c0tXXXXCXXXXXXXXXXXd0 - - 9 5 1.29M 817K # c0tXXXXCXXXXXXXXXXXd0 - - 9 5 1.29M 817K # ------------------------- ----- ----- ----- ----- ----- ----- # ===================================================================== ## parse iostat output # NOTE: hardcode the header # the double header line is hard to parse, we opt to # hardcode the header fields header = [ 'name', 'capacity-alloc', 'capacity-free', 'operations-read', 'operations-write', 'bandwith-read', 'bandwith-write', ] root_vdev = None vdev = None dev = None current_data = OrderedDict() for line in res['stdout'].splitlines(): # NOTE: skip header if line.strip() == '' or \ line.strip().split()[-1] in ['write', 'bandwidth']: continue # NOTE: reset pool on line separator if line.startswith('-') and line.endswith('-'): ret.update(current_data) current_data = OrderedDict() continue # NOTE: transform data into dict io_data = OrderedDict( list( zip( header, [x for x in line.strip().split(' ') if x not in ['']], ))) # NOTE: normalize values if parsable: # NOTE: raw numbers and pythonic types io_data = __utils__['zfs.from_auto_dict'](io_data) else: # NOTE: human readable zfs types io_data = __utils__['zfs.to_auto_dict'](io_data) # NOTE: store io_data in the proper location if line.startswith(' ' * 4): dev = io_data['name'] current_data[root_vdev][vdev][dev] = io_data elif line.startswith(' ' * 2): dev = None vdev = io_data['name'] current_data[root_vdev][vdev] = io_data else: dev = vdev = None root_vdev = io_data['name'] current_data[root_vdev] = io_data # NOTE: name already used as identifier, drop duplicate data del io_data['name'] return ret
def managed(name, entries, connect_spec=None): """Ensure the existence (or not) of LDAP entries and their attributes Example: .. code-block:: yaml ldapi:///: ldap.managed: - connect_spec: bind: method: sasl - entries: # make sure the entry doesn't exist - cn=foo,ou=users,dc=example,dc=com: - delete_others: True # make sure the entry exists with only the specified # attribute values - cn=admin,dc=example,dc=com: - delete_others: True - replace: cn: - admin description: - LDAP administrator objectClass: - simpleSecurityObject - organizationalRole userPassword: - {{pillar.ldap_admin_password}} # make sure the entry exists, its olcRootDN attribute # has only the specified value, the olcRootDN attribute # doesn't exist, and all other attributes are ignored - 'olcDatabase={1}hdb,cn=config': - replace: olcRootDN: - cn=admin,dc=example,dc=com # the admin entry has its own password attribute olcRootPW: [] # note the use of 'default'. also note how you don't # have to use list syntax if there is only one attribute # value - cn=foo,ou=users,dc=example,dc=com: - delete_others: True - default: userPassword: changeme shadowLastChange: 0 # keep sshPublicKey if present, but don't create # the attribute if it is missing sshPublicKey: [] - replace: cn: foo uid: foo uidNumber: 1000 gidNumber: 1000 gecos: Foo Bar givenName: Foo sn: Bar homeDirectory: /home/foo loginShell: /bin/bash objectClass: - inetOrgPerson - posixAccount - top - ldapPublicKey - shadowAccount :param name: The URL of the LDAP server. This is ignored if ``connect_spec`` is either a connection object or a dict with a ``'url'`` entry. :param entries: A description of the desired state of zero or more LDAP entries. ``entries`` is an iterable of dicts. Each of these dict's keys are the distinguished names (DNs) of LDAP entries to manage. Each of these dicts is processed in order. A later dict can reference an LDAP entry that was already mentioned in an earlier dict, which makes it possible for later dicts to enhance or alter the desired state of an LDAP entry. The DNs are mapped to a description of the LDAP entry's desired state. These LDAP entry descriptions are themselves iterables of dicts. Each dict in the iterable is processed in order. They contain directives controlling the entry's state. The key names the directive type and the value is state information for the directive. The specific structure of the state information depends on the directive type. The structure of ``entries`` looks like this:: [{dn1: [{directive1: directive1_state, directive2: directive2_state}, {directive3: directive3_state}], dn2: [{directive4: directive4_state, directive5: directive5_state}]}, {dn3: [{directive6: directive6_state}]}] These are the directives: * ``'delete_others'`` Boolean indicating whether to delete attributes not mentioned in this dict or any of the other directive dicts for this DN. Defaults to ``False``. If you don't want to delete an attribute if present, but you also don't want to add it if it is missing or modify it if it is present, you can use either the ``'default'`` directive or the ``'add'`` directive with an empty value list. * ``'default'`` A dict mapping an attribute name to an iterable of default values for that attribute. If the attribute already exists, it is left alone. If not, it is created using the given list of values. An empty value list is useful when you don't want to create an attribute if it is missing but you do want to preserve it if the ``'delete_others'`` key is ``True``. * ``'add'`` Attribute values to add to the entry. This is a dict mapping an attribute name to an iterable of values to add. An empty value list is useful when you don't want to create an attribute if it is missing but you do want to preserve it if the ``'delete_others'`` key is ``True``. * ``'delete'`` Attribute values to remove from the entry. This is a dict mapping an attribute name to an iterable of values to delete from the attribute. If the iterable is empty, all of the attribute's values are deleted. * ``'replace'`` Attributes to replace. This is a dict mapping an attribute name to an iterable of values. Any existing values for the attribute are deleted, then the given values are added. The iterable may be empty. In the above directives, the iterables of attribute values may instead be ``None``, in which case an empty list is used, or a scalar such as a string or number, in which case a new list containing the scalar is used. Note that if all attribute values are removed from an entry, the entire entry is deleted. :param connect_spec: See the description of the ``connect_spec`` parameter of the :py:func:`ldap3.connect <salt.modules.ldap3.connect>` function in the :py:mod:`ldap3 <salt.modules.ldap3>` execution module. If this is a dict and the ``'url'`` entry is not specified, the ``'url'`` entry is set to the value of the ``name`` parameter. :returns: A dict with the following keys: * ``'name'`` This is the same object passed to the ``name`` parameter. * ``'changes'`` This is a dict describing the changes made (or, in test mode, the changes that would have been attempted). If no changes were made (or no changes would have been attempted), then this dict is empty. Only successful changes are included. Each key is a DN of an entry that was changed (or would have been changed). Entries that were not changed (or would not have been changed) are not included. The value is a dict with two keys: * ``'old'`` The state of the entry before modification. If the entry did not previously exist, this key maps to ``None``. Otherwise, the value is a dict mapping each of the old entry's attributes to a list of its values before any modifications were made. Unchanged attributes are excluded from this dict. * ``'new'`` The state of the entry after modification. If the entry was deleted, this key maps to ``None``. Otherwise, the value is a dict mapping each of the entry's attributes to a list of its values after the modifications were made. Unchanged attributes are excluded from this dict. Example ``'changes'`` dict where a new entry was created with a single attribute containing two values:: {'dn1': {'old': None, 'new': {'attr1': ['val1', 'val2']}}} Example ``'changes'`` dict where a new attribute was added to an existing entry:: {'dn1': {'old': {}, 'new': {'attr2': ['val3']}}} * ``'result'`` One of the following values: * ``True`` if no changes were necessary or if all changes were applied successfully. * ``False`` if at least one change was unable to be applied. * ``None`` if changes would be applied but it is in test mode. """ if connect_spec is None: connect_spec = {} try: connect_spec.setdefault("url", name) except AttributeError: # already a connection object pass connect = __salt__["ldap3.connect"] # hack to get at the ldap3 module to access the ldap3.LDAPError # exception class. https://github.com/saltstack/salt/issues/27578 ldap3 = inspect.getmodule(connect) with connect(connect_spec) as l: old, new = _process_entries(l, entries) # collect all of the affected entries (only the key is # important in this dict; would have used an OrderedSet if # there was one) dn_set = OrderedDict() dn_set.update(old) dn_set.update(new) # do some cleanup dn_to_delete = set() for dn in dn_set: o = old.get(dn, {}) n = new.get(dn, {}) for x in o, n: to_delete = set() for attr, vals in x.items(): if not vals: # clean out empty attribute lists to_delete.add(attr) for attr in to_delete: del x[attr] if o == n: # clean out unchanged entries dn_to_delete.add(dn) for dn in dn_to_delete: for x in old, new: x.pop(dn, None) del dn_set[dn] ret = { "name": name, "changes": {}, "result": None, "comment": "", } if old == new: ret["comment"] = "LDAP entries already set" ret["result"] = True return ret if __opts__["test"]: ret["comment"] = "Would change LDAP entries" changed_old = old changed_new = new success_dn_set = dn_set else: # execute the changes changed_old = OrderedDict() changed_new = OrderedDict() # assume success; these will be changed on error ret["result"] = True ret["comment"] = "Successfully updated LDAP entries" errs = [] success_dn_set = OrderedDict() for dn in dn_set: o = old.get(dn, {}) n = new.get(dn, {}) try: # perform the operation if o: if n: op = "modify" assert o != n __salt__["ldap3.change"](l, dn, o, n) else: op = "delete" __salt__["ldap3.delete"](l, dn) else: op = "add" assert n __salt__["ldap3.add"](l, dn, n) # update these after the op in case an exception # is raised changed_old[dn] = o changed_new[dn] = n success_dn_set[dn] = True except ldap3.LDAPError as err: log.exception("failed to %s entry %s (%s)", op, dn, err) errs.append((op, dn, err)) continue if errs: ret["result"] = False ret["comment"] = "failed to " + ", ".join( (op + " entry " + dn + "(" + str(err) + ")" for op, dn, err in errs)) # set ret['changes']. filter out any unchanged attributes, and # convert the value sets to lists before returning them to the # user (sorted for easier comparisons) for dn in success_dn_set: o = changed_old.get(dn, {}) n = changed_new.get(dn, {}) changes = {} ret["changes"][dn] = changes for x, xn in ((o, "old"), (n, "new")): if not x: changes[xn] = None continue changes[xn] = { attr: sorted(vals) for attr, vals in x.items() if o.get(attr, ()) != n.get(attr, ()) } return ret
def managed(name, entries, connect_spec=None): '''Ensure the existance (or not) of LDAP entries and their attributes Example: .. code-block:: yaml ldapi:///: ldap.managed: - connect_spec: bind: method: sasl - entries: # make sure the entry doesn't exist - cn=foo,ou=users,dc=example,dc=com: - delete_others: True # make sure the entry exists with only the specified # attribute values - cn=admin,dc=example,dc=com: - delete_others: True - replace: cn: - admin description: - LDAP administrator objectClass: - simpleSecurityObject - organizationalRole userPassword: - {{pillar.ldap_admin_password}} # make sure the entry exists, its olcRootDN attribute # has only the specified value, the olcRootDN attribute # doesn't exist, and all other attributes are ignored - 'olcDatabase={1}hdb,cn=config': - replace: olcRootDN: - cn=admin,dc=example,dc=com # the admin entry has its own password attribute olcRootPW: [] # note the use of 'default'. also note how you don't # have to use list syntax if there is only one attribute # value - cn=foo,ou=users,dc=example,dc=com: - delete_others: True - default: userPassword: changeme shadowLastChange: 0 # keep sshPublicKey if present, but don't create # the attribute if it is missing sshPublicKey: [] - replace: cn: foo uid: foo uidNumber: 1000 gidNumber: 1000 gecos: Foo Bar givenName: Foo sn: Bar homeDirectory: /home/foo loginShell: /bin/bash objectClass: - inetOrgPerson - posixAccount - top - ldapPublicKey - shadowAccount :param name: The URL of the LDAP server. This is ignored if ``connect_spec`` is either a connection object or a dict with a ``'url'`` entry. :param entries: A description of the desired state of zero or more LDAP entries. ``entries`` is an iterable of dicts. Each of these dict's keys are the distinguished names (DNs) of LDAP entries to manage. Each of these dicts is processed in order. A later dict can reference an LDAP entry that was already mentioned in an earlier dict, which makes it possible for later dicts to enhance or alter the desired state of an LDAP entry. The DNs are mapped to a description of the LDAP entry's desired state. These LDAP entry descriptions are themselves iterables of dicts. Each dict in the iterable is processed in order. They contain directives controlling the entry's state. The key names the directive type and the value is state information for the directive. The specific structure of the state information depends on the directive type. The structure of ``entries`` looks like this:: [{dn1: [{directive1: directive1_state, directive2: directive2_state}, {directive3: directive3_state}], dn2: [{directive4: directive4_state, directive5: directive5_state}]}, {dn3: [{directive6: directive6_state}]}] These are the directives: * ``'delete_others'`` Boolean indicating whether to delete attributes not mentioned in this dict or any of the other directive dicts for this DN. Defaults to ``False``. If you don't want to delete an attribute if present, but you also don't want to add it if it is missing or modify it if it is present, you can use either the ``'default'`` directive or the ``'add'`` directive with an empty value list. * ``'default'`` A dict mapping an attribute name to an iterable of default values for that attribute. If the attribute already exists, it is left alone. If not, it is created using the given list of values. An empty value list is useful when you don't want to create an attribute if it is missing but you do want to preserve it if the ``'delete_others'`` key is ``True``. * ``'add'`` Attribute values to add to the entry. This is a dict mapping an attribute name to an iterable of values to add. An empty value list is useful when you don't want to create an attribute if it is missing but you do want to preserve it if the ``'delete_others'`` key is ``True``. * ``'delete'`` Attribute values to remove from the entry. This is a dict mapping an attribute name to an iterable of values to delete from the attribute. If the iterable is empty, all of the attribute's values are deleted. * ``'replace'`` Attributes to replace. This is a dict mapping an attribute name to an iterable of values. Any existing values for the attribute are deleted, then the given values are added. The iterable may be empty. In the above directives, the iterables of attribute values may instead be ``None``, in which case an empty list is used, or a scalar such as a string or number, in which case a new list containing the scalar is used. Note that if all attribute values are removed from an entry, the entire entry is deleted. :param connect_spec: See the description of the ``connect_spec`` parameter of the :py:func:`ldap3.connect <salt.modules.ldap3.connect>` function in the :py:mod:`ldap3 <salt.modules.ldap3>` execution module. If this is a dict and the ``'url'`` entry is not specified, the ``'url'`` entry is set to the value of the ``name`` parameter. :returns: A dict with the following keys: * ``'name'`` This is the same object passed to the ``name`` parameter. * ``'changes'`` This is a dict describing the changes made (or, in test mode, the changes that would have been attempted). If no changes were made (or no changes would have been attempted), then this dict is empty. Only successful changes are included. Each key is a DN of an entry that was changed (or would have been changed). Entries that were not changed (or would not have been changed) are not included. The value is a dict with two keys: * ``'old'`` The state of the entry before modification. If the entry did not previously exist, this key maps to ``None``. Otherwise, the value is a dict mapping each of the old entry's attributes to a list of its values before any modifications were made. Unchanged attributes are excluded from this dict. * ``'new'`` The state of the entry after modification. If the entry was deleted, this key maps to ``None``. Otherwise, the value is a dict mapping each of the entry's attributes to a list of its values after the modifications were made. Unchanged attributes are excluded from this dict. Example ``'changes'`` dict where a new entry was created with a single attribute containing two values:: {'dn1': {'old': None, 'new': {'attr1': ['val1', 'val2']}}} Example ``'changes'`` dict where a new attribute was added to an existing entry:: {'dn1': {'old': {}, 'new': {'attr2': ['val3']}}} * ``'result'`` One of the following values: * ``True`` if no changes were necessary or if all changes were applied successfully. * ``False`` if at least one change was unable to be applied. * ``None`` if changes would be applied but it is in test mode. ''' if connect_spec is None: connect_spec = {} try: connect_spec.setdefault('url', name) except AttributeError: # already a connection object pass connect = __salt__['ldap3.connect'] # hack to get at the ldap3 module to access the ldap3.LDAPError # exception class. https://github.com/saltstack/salt/issues/27578 ldap3 = inspect.getmodule(connect) with connect(connect_spec) as l: old, new = _process_entries(l, entries) # collect all of the affected entries (only the key is # important in this dict; would have used an OrderedSet if # there was one) dn_set = OrderedDict() dn_set.update(old) dn_set.update(new) # do some cleanup dn_to_delete = set() for dn in dn_set: o = old.get(dn, {}) n = new.get(dn, {}) for x in o, n: to_delete = set() for attr, vals in six.iteritems(x): if not len(vals): # clean out empty attribute lists to_delete.add(attr) for attr in to_delete: del x[attr] if o == n: # clean out unchanged entries dn_to_delete.add(dn) for dn in dn_to_delete: for x in old, new: x.pop(dn, None) del dn_set[dn] ret = { 'name': name, 'changes': {}, 'result': None, 'comment': '', } if old == new: ret['comment'] = 'LDAP entries already set' ret['result'] = True return ret if __opts__['test']: ret['comment'] = 'Would change LDAP entries' changed_old = old changed_new = new success_dn_set = dn_set else: # execute the changes changed_old = OrderedDict() changed_new = OrderedDict() # assume success; these will be changed on error ret['result'] = True ret['comment'] = 'Successfully updated LDAP entries' errs = [] success_dn_set = OrderedDict() for dn in dn_set: o = old.get(dn, {}) n = new.get(dn, {}) try: # perform the operation if len(o): if len(n): op = 'modify' assert o != n __salt__['ldap3.change'](l, dn, o, n) else: op = 'delete' __salt__['ldap3.delete'](l, dn) else: op = 'add' assert len(n) __salt__['ldap3.add'](l, dn, n) # update these after the op in case an exception # is raised changed_old[dn] = o changed_new[dn] = n success_dn_set[dn] = True except ldap3.LDAPError: log.exception('failed to %s entry %s', op, dn) errs.append((op, dn)) continue if len(errs): ret['result'] = False ret['comment'] = 'failed to ' \ + ', '.join((op + ' entry ' + dn for op, dn in errs)) # set ret['changes']. filter out any unchanged attributes, and # convert the value sets to lists before returning them to the # user (sorted for easier comparisons) for dn in success_dn_set: o = changed_old.get(dn, {}) n = changed_new.get(dn, {}) changes = {} ret['changes'][dn] = changes for x, xn in ((o, 'old'), (n, 'new')): if not len(x): changes[xn] = None continue changes[xn] = dict(((attr, sorted(vals)) for attr, vals in six.iteritems(x) if o.get(attr, ()) != n.get(attr, ()))) return ret
def gen_functions(self, pack=None, virtual_enable=True, whitelist=None, provider_overrides=False): ''' Return a dict of functions found in the defined module_dirs ''' funcs = OrderedDict() self.load_modules() for mod in self.modules: # If this is a proxy minion then MOST modules cannot work. Therefore, require that # any module that does work with salt-proxy-minion define __proxyenabled__ as a list # containing the names of the proxy types that the module supports. if not hasattr(mod, 'render') and 'proxy' in self.opts: if not hasattr(mod, '__proxyenabled__'): # This is a proxy minion but this module doesn't support proxy # minions at all continue if not (self.opts['proxy']['proxytype'] in mod.__proxyenabled__ or '*' in mod.__proxyenabled__): # This is a proxy minion, this module supports proxy # minions, but not this particular minion log.debug(mod) continue if hasattr(mod, '__opts__'): mod.__opts__.update(self.opts) else: mod.__opts__ = self.opts mod.__grains__ = self.grains mod.__pillar__ = self.pillar if pack: if isinstance(pack, list): for chunk in pack: if not isinstance(chunk, dict): continue try: setattr(mod, chunk['name'], chunk['value']) except KeyError: pass else: setattr(mod, pack['name'], pack['value']) # Call a module's initialization method if it exists if hasattr(mod, '__init__'): if callable(mod.__init__): try: mod.__init__(self.opts) except TypeError: pass # Trim the full pathname to just the module # this will be the short name that other salt modules and state # will refer to it as. module_name = mod.__name__.rsplit('.', 1)[-1] if virtual_enable: # if virtual modules are enabled, we need to look for the # __virtual__() function inside that module and run it. (virtual_ret, virtual_name) = self.process_virtual(mod, module_name) # if process_virtual returned a non-True value then we are # supposed to not process this module if virtual_ret is not True: continue # update our module name to reflect the virtual name module_name = virtual_name if whitelist: # If a whitelist is defined then only load the module if it is # in the whitelist if module_name not in whitelist: continue # load the functions from the module and update our dict funcs.update(self.load_functions(mod, module_name)) # Handle provider overrides if provider_overrides and self.opts.get('providers', False): if isinstance(self.opts['providers'], dict): for mod, provider in self.opts['providers'].items(): newfuncs = raw_mod(self.opts, provider, funcs) if newfuncs: for newfunc in newfuncs: f_key = '{0}{1}'.format( mod, newfunc[newfunc.rindex('.'):] ) funcs[f_key] = newfuncs[newfunc] # now that all the functions have been collected, iterate back over # the available modules and inject the special __salt__ namespace that # contains these functions. for mod in self.modules: if not hasattr(mod, '__salt__') or ( not in_pack(pack, '__salt__') and (not str(mod.__name__).startswith('salt.loaded.int.grain') and not str(mod.__name__).startswith('salt.loaded.ext.grain')) ): mod.__salt__ = funcs elif not in_pack(pack, '__salt__') and \ (str(mod.__name__).startswith('salt.loaded.int.grain') or str(mod.__name__).startswith('salt.loaded.ext.grain')): mod.__salt__.update(funcs) return funcs
def serialize(cls, id_=None): # The order matters serialized = OrderedDict() if id_ is not None: # This is meant as a configuration section, sub json schema serialized['id'] = '{0}/{1}.json#'.format(BASE_SCHEMA_URL, id_) else: # Main configuration block, json schema serialized['$schema'] = 'http://json-schema.org/draft-04/schema#' if cls.title is not None: serialized['title'] = cls.title if cls.description is not None: if cls.description == cls.__doc__: serialized['description'] = textwrap.dedent(cls.description).strip() else: serialized['description'] = cls.description required = [] ordering = [] serialized['type'] = 'object' properties = OrderedDict() cls.after_items_update = [] for name in cls._order: skip_order = False if name in cls._sections: section = cls._sections[name] serialized_section = section.serialize(None if section.__flatten__ is True else name) if section.__flatten__ is True: # Flatten the configuration section into the parent # configuration properties.update(serialized_section['properties']) if 'x-ordering' in serialized_section: ordering.extend(serialized_section['x-ordering']) if 'required' in serialized_section: required.extend(serialized_section['required']) if hasattr(section, 'after_items_update'): cls.after_items_update.extend(section.after_items_update) skip_order = True else: # Store it as a configuration section properties[name] = serialized_section if name in cls._items: config = cls._items[name] # Handle the configuration items defined in the class instance if config.__flatten__ is True: serialized_config = config.serialize() cls.after_items_update.append(serialized_config) skip_order = True else: properties[name] = config.serialize() if config.required: # If it's a required item, add it to the required list required.append(name) if skip_order is False: # Store the order of the item if name not in ordering: ordering.append(name) if properties: serialized['properties'] = properties # Update the serialized object with any items to include after properties if cls.after_items_update: after_items_update = {} for entry in cls.after_items_update: name, data = next(six.iteritems(entry)) if name in after_items_update: after_items_update[name].extend(data) else: after_items_update[name] = data serialized.update(after_items_update) if required: # Only include required if not empty serialized['required'] = required if ordering: # Only include ordering if not empty serialized['x-ordering'] = ordering serialized['additionalProperties'] = cls.__allow_additional_items__ return serialized