Manage grains using support metadata

Change-Id: I1e1269268a81d8cd01b5fe9328f63e8bf85e941b
diff --git a/salt/map.jinja b/salt/map.jinja
index 3ed0070..8693250 100644
--- a/salt/map.jinja
+++ b/salt/map.jinja
@@ -89,11 +89,15 @@
 Arch:
   pkgs:
   - salt-zmq
+  grains_validity_pkgs:
+    - python-yaml
 Debian:
   pkgs:
   - salt-minion
   - python-m2crypto
   - python-psutil
+  grains_validity_pkgs:
+    - python-yaml
 Gentoo:
   pkgs:
   - app-admin/salt
@@ -105,6 +109,8 @@
   - salt-minion
   - python-m2ext
   - python-psutil
+  grains_validity_pkgs:
+    - PyYaml
 {%- endload %}
 
 {%- if pillar.salt.minion is defined %}
diff --git a/salt/minion/grains.sls b/salt/minion/grains.sls
index 86e9987..dab3585 100644
--- a/salt/minion/grains.sls
+++ b/salt/minion/grains.sls
@@ -22,23 +22,48 @@
   - require:
     - file: salt_minion_grains_dir
 
-{%- set new_grains = salt['cmd.run']('cat /etc/salt/grains.d/*') %}
-{%- set old_grains = salt['cmd.run']('cat /etc/salt/grains') %}
+salt_minion_grains_pkg_validity_check:
+  pkg.installed:
+  - pkgs: {{ minion.grains_validity_pkgs }}
 
-{%- if new_grains != old_grains %}
+{%- for service_name, service in pillar.items() %}
+  {%- set support_fragment_file = service_name+'/meta/salt.yml' %}
+  {%- macro load_support_file() %}{% include support_fragment_file ignore missing %}{% endmacro %}
+  {%- set support_yaml = load_support_file()|load_yaml %}
+
+  {%- if support_yaml %}
+    {%- for name, grain in support_yaml.get('grain', {}).iteritems() %}
+salt_minion_grain_{{ service_name }}_{{ name }}:
+  file.managed:
+    - name: /etc/salt/grains.d/{{ name }}
+    - contents: |
+        {{ grain|yaml(False)|indent(8) }}
+    - require:
+      - file: salt_minion_grains_dir
+
+salt_minion_grain_{{ service_name }}_{{ name }}_validity_check:
+  cmd.wait:
+    - name: python -c "import yaml; stream = file('/etc/salt/grains.d/{{ name }}', 'r'); yaml.load(stream); stream.close()"
+    - require:
+      - pkg: salt_minion_grains_pkg_validity_check
+    - watch:
+      - file: salt_minion_grain_{{ service_name }}_{{ name }}
+    - watch_in:
+      - cmd: salt_minion_grains_file
+    {%- endfor %}
+  {%- endif %}
+{%- endfor %}
 
 salt_minion_grains_file:
-  cmd.run:
+  cmd.wait:
   - name: cat /etc/salt/grains.d/* > /etc/salt/grains
   - require:
     - file: salt_minion_grains_files
 
 salt_minion_grains_publish:
-  module.run:
+  module.wait:
   - name: mine.update
-  - require:
+  - watch:
     - cmd: salt_minion_grains_file
 
 {%- endif %}
-
-{%- endif %}