{"action":"created","issue":{"url":"https://api.github.com/repos/saltstack/salt/issues/42349","repository_url":"https://api.github.com/repos/saltstack/salt","labels_url":"https://api.github.com/repos/saltstack/salt/issues/42349/labels{/name}","comments_url":"https://api.github.com/repos/saltstack/salt/issues/42349/comments","events_url":"https://api.github.com/repos/saltstack/salt/issues/42349/events","html_url":"https://github.com/saltstack/salt/pull/42349","id":243515453,"node_id":"MDExOlB1bGxSZXF1ZXN0MTMwOTQyNTgw","number":42349,"title":"New pillar/master_tops saltclass module","user":{"login":"olivier-mauras","id":1299371,"node_id":"MDQ6VXNlcjEyOTkzNzE=","avatar_url":"https://avatars3.githubusercontent.com/u/1299371?v=4","gravatar_id":"","url":"https://api.github.com/users/olivier-mauras","html_url":"https://github.com/olivier-mauras","followers_url":"https://api.github.com/users/olivier-mauras/followers","following_url":"https://api.github.com/users/olivier-mauras/following{/other_user}","gists_url":"https://api.github.com/users/olivier-mauras/gists{/gist_id}","starred_url":"https://api.github.com/users/olivier-mauras/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/olivier-mauras/subscriptions","organizations_url":"https://api.github.com/users/olivier-mauras/orgs","repos_url":"https://api.github.com/users/olivier-mauras/repos","events_url":"https://api.github.com/users/olivier-mauras/events{/privacy}","received_events_url":"https://api.github.com/users/olivier-mauras/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":28,"created_at":"2017-07-17T20:21:37Z","updated_at":"2018-06-15T07:21:46Z","closed_at":"2017-09-28T12:26:46Z","author_association":"CONTRIBUTOR","pull_request":{"url":"https://api.github.com/repos/saltstack/salt/pulls/42349","html_url":"https://github.com/saltstack/salt/pull/42349","diff_url":"https://github.com/saltstack/salt/pull/42349.diff","patch_url":"https://github.com/saltstack/salt/pull/42349.patch"},"body":"### What does this PR do?\r\nIt provides a new pillar/master_tops module called `saltclass`.  \r\nThis module clones the behaviour of reclass, without the need of an external app, and add a couple of features to improve flexibility.  \r\n\r\n### Features\r\n\r\n- Define your nodes through class inheritance\r\n- Reuse your reclass datas with minimal modifications\r\n    - `applications` => `states`\r\n    - `parameters` => `pillars`\r\n    `for i in $(grep -r -e applications: -e parameters: -l <your_reclass_path>); do sed -i 's/applications:/states:/g;s/parameters:/pillars:/g' $i; done`\r\n- Use Jinja templating in your yaml definitions\r\n- Access to the following Salt objects in Jinja\r\n    - `__opts__`\r\n    - `__salt__`\r\n    - `__grains__`\r\n    - `__pillars__`\r\n    - `minion_id`\r\n- Chose how to merge or override your lists using `^` character (see examples)\r\n- Expand variables `${}` with possibility to escape them if needed `\\${}` (see examples)\r\n- Ignores missing node/class and will simply return empty without breaking the pillar module completely - will be logged\r\n\r\n### Configuration\r\n``` yaml\r\n  ext_pillar:\r\n    - saltclass:\r\n      - path: /srv/saltclass\r\n\r\n  master_tops:\r\n    saltclass:\r\n      path: /srv/saltclass\r\n```\r\n\r\n### Examples\r\n\r\nBasic jinja + grains example\r\n``` yaml\r\n# /srv/saltclass/nodes/minion.domain.yml\r\nenvironment: prod\r\nclasses:\r\n{% for class in ['default', 'app1'] %}\r\n  - {{ class }}\r\n{% endfor %}\r\n  - {{ __grains__['os'] }}\r\n\r\npillars:\r\n  default:\r\n    network:\r\n      dns:\r\n        srv3: 192.168.1.1\r\n    os: {{ __grains__['oscodename'] }}\r\n```\r\nList merge example\r\n``` yaml\r\n# /srv/saltclass/classes/list.yml\r\npillars:\r\n  list:\r\n    - v1\r\n    - v2\r\n\r\n# /srv/saltclass/nodes/minion.domain.yml\r\nclasses:\r\n  - list\r\n\r\npillars:\r\n  list:\r\n    - v3\r\n    - v4\r\n# This list will be appended to the one from list class and you will end up with:\r\n# list:\r\n#   - v1\r\n#   - v2\r\n#   - v3\r\n#   - v4\r\n# To override the list use ^ as your first list entry\r\npillars:\r\n  list:\r\n    - ^\r\n    - v1\r\n    - v4\r\n    - v5\r\n# Will give you:\r\n# list:\r\n#   - v1\r\n#   - v4\r\n#   - v5\r\n```\r\n\r\nVariables expansion\r\n``` yaml\r\n# _test/classes/default.yml\r\npillars:\r\n  default:\r\n    test:\r\n      list:\r\n        - l1\r\n        - l2\r\n        - l3\r\n  default2:\r\n    expansion:\r\n      going:\r\n        down:\r\n          some: more\r\n\r\n# _test/nodes/alpine.internal.yml\r\npillars:\r\n  borg:\r\n    server: other.xxx.xxx\r\n  override:\r\n    testing:\r\n      variable:\r\n        string: ${default2:expansion:going:down:some}               # Will be expanded to 'more'\r\n        list_: ${default:test2:list}                                # Will be expanded to ['l1', 'l2', 'l3']\r\n        inline_expansion: 'borg server is ${borg:server}'           # Will be expanded to 'borg server is other.xxx.xxx'\r\n        inline_expansion_escape: 'borg server is \\${borg:server}'   # Will be expanded to 'borg server is ${borg:server}'\r\n        unknown_expansion: ${class4:unknown:variables}              # Will be expanded to '${class4:unknown:variables}'\r\n```\r\nAn example subset of datas is available here: http://git.mauras.ch/salt/saltclass/src/master/examples  \r\nAlthough useless it gives a pretty good idea how to layout your class hierarchy.  \r\n \r\nIntegrated documentation is pretty scarse at the moment, I'll try to improve that ASAP\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/saltstack/salt/issues/comments/397536143","html_url":"https://github.com/saltstack/salt/pull/42349#issuecomment-397536143","issue_url":"https://api.github.com/repos/saltstack/salt/issues/42349","id":397536143,"node_id":"MDEyOklzc3VlQ29tbWVudDM5NzUzNjE0Mw==","user":{"login":"max-arnold","id":370942,"node_id":"MDQ6VXNlcjM3MDk0Mg==","avatar_url":"https://avatars0.githubusercontent.com/u/370942?v=4","gravatar_id":"","url":"https://api.github.com/users/max-arnold","html_url":"https://github.com/max-arnold","followers_url":"https://api.github.com/users/max-arnold/followers","following_url":"https://api.github.com/users/max-arnold/following{/other_user}","gists_url":"https://api.github.com/users/max-arnold/gists{/gist_id}","starred_url":"https://api.github.com/users/max-arnold/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/max-arnold/subscriptions","organizations_url":"https://api.github.com/users/max-arnold/orgs","repos_url":"https://api.github.com/users/max-arnold/repos","events_url":"https://api.github.com/users/max-arnold/events{/privacy}","received_events_url":"https://api.github.com/users/max-arnold/received_events","type":"User","site_admin":false},"created_at":"2018-06-15T07:21:45Z","updated_at":"2018-06-15T07:21:45Z","author_association":"NONE","body":"Is it really necessary to rescan the directory tree on each `get_class()` invocation?\r\n\r\n```\r\n> /Users/user/.virtualenvs/salt-2018/lib/python2.7/site-packages/salt/utils/saltclass.py(55)get_class()\r\n     54     for root, dirs, files in salt.utils.path.os_walk(os.path.join(saltclass_path, 'classes')):\r\n     55         for l_file in files:\r\n     56             l_files.append(os.path.join(root, l_file))\r\n```"}}
{"actor":{"display_login":"max-arnold"}}