Merge "Generate metrics from logs"
diff --git a/.kitchen.travis.yml b/.kitchen.travis.yml
deleted file mode 100644
index a1d3e04..0000000
--- a/.kitchen.travis.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-suites:
-
-  - name: <%= ENV['SUITE'] %>
-    provisioner:
-      pillars-from-files:
-        linux.sls: tests/pillar/<%= ENV['SUITE'] %>.sls
diff --git a/.travis.yml b/.travis.yml
index 3e54539..714c249 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -34,7 +34,8 @@
   - make test | tail
 
 script:
-  - KITCHEN_LOCAL_YAML=.kitchen.travis.yml bundle exec kitchen test -t tests/integration
+  - test ! -e .kitchen.yml || bundle exec kitchen converge ${SUITE} || true
+  - test ! -e .kitchen.yml || bundle exec kitchen verify ${SUITE} -t tests/integration
 
 notifications:
   webhooks:
diff --git a/README.rst b/README.rst
index b90c0f5..930557b 100644
--- a/README.rst
+++ b/README.rst
@@ -420,6 +420,68 @@
         cpu:
           governor: performance
 
+
+CGROUPS
+~~~~~~~
+
+Setup linux cgroups:
+
+.. code-block:: yaml
+
+    linux:
+      system:
+        cgroup:
+          enabled: true
+          group:
+            ceph_group_1:
+              controller:
+                cpu:
+                  shares:
+                    value: 250
+                cpuacct:
+                  usage:
+                    value: 0
+                cpuset:
+                  cpus:
+                    value: 1,2,3
+                memory:
+                  limit_in_bytes:
+                    value: 2G
+                  memsw.limit_in_bytes:
+                    value: 3G
+              mapping:
+                subjects:
+                - '@ceph'
+            generic_group_1:
+              controller:
+                cpu:
+                  shares:
+                    value: 250
+                cpuacct:
+                  usage:
+                    value: 0
+              mapping:
+                subjects:
+                - '*:firefox'
+                - 'student:cp'
+
+
+Shared Libraries
+~~~~~~~~~~~~~~~~
+
+Set additional shared library to Linux system library path
+
+.. code-block:: yaml
+
+    linux:
+      system:
+        ld:
+          library:
+            java:
+              - /usr/lib/jvm/jre-openjdk/lib/amd64/server
+              - /opt/java/jre/lib/amd64/server
+    
+
 Certificates
 ~~~~~~~~~~~~
 
@@ -993,6 +1055,27 @@
             mtu: 9100
             ipflush_onchange: true
 
+Debian static proto interfaces
+
+When you are changing interface proto from dhcp in up state to static, you
+may need to flush ip addresses and restart interface to assign ip address from a managed file.
+For example, if you want to use the interface and the ip on the bridge.
+This can be done by setting the ``ipflush_onchange`` with combination
+``restart_on_ipflush`` param set to to true.
+
+.. code-block:: yaml
+
+    linux:
+      network:
+        interface:
+          eth1:
+            enabled: true
+            type: eth
+            proto: static
+            address: 10.1.0.22
+            netmask: 255.255.255.0
+            ipflush_onchange: true
+            restart_on_ipflush: true
 
 Concatinating and removing interface files
 
diff --git a/debian/control b/debian/control
index d634b75..9667ad4 100644
--- a/debian/control
+++ b/debian/control
@@ -10,6 +10,6 @@
 
 Package: salt-formula-linux
 Architecture: all
-Depends: ${misc:Depends}, salt-master, reclass
+Depends: ${misc:Depends}
 Description: Linux salt formula
  Configure Linux operating system.
diff --git a/linux/files/cgconfig.conf b/linux/files/cgconfig.conf
new file mode 100644
index 0000000..0ea2e75
--- /dev/null
+++ b/linux/files/cgconfig.conf
@@ -0,0 +1,16 @@
+{%- from "linux/map.jinja" import system with context -%}
+##
+## This is cgconfig configuration file is managed by Salt
+##
+{%- for cgroup_name, cg in system.cgroup.group.iteritems() %}
+group {{ cgroup_name }} {
+  {%- for controller_name, controller in cg.controller.iteritems() %}
+        {{ controller_name }} {
+    {%- for v_name, v in controller.iteritems() %}
+                {{ controller_name }}.{{ v_name }}="{{ v.value }}";
+    {%- endfor %}
+
+        }
+  {%- endfor %}
+}
+{%- endfor %}
diff --git a/linux/files/cgrules.conf b/linux/files/cgrules.conf
new file mode 100644
index 0000000..116a9d6
--- /dev/null
+++ b/linux/files/cgrules.conf
@@ -0,0 +1,10 @@
+{%- from "linux/map.jinja" import system with context -%}
+##
+## This is cgrules configuration file is managed by Salt
+##
+#<user/group>         <controller(s)>         <cgroup>
+{%- for cgroup_name, cg in system.cgroup.group.iteritems() %}
+{%- for subject in cg.mapping.subjects %}
+{{ subject }}{% raw %}         {% endraw %}{%- for controller_name, controller in cg.controller.iteritems() -%}{{ controller_name }}{%- if not loop.last -%},{%- endif -%}{%- endfor -%}{% raw %}         {% endraw %}{{ cgroup_name }}
+{%- endfor %}
+{%- endfor %}
diff --git a/linux/network/interface.sls b/linux/network/interface.sls
index 921ceac..b9c1c41 100644
--- a/linux/network/interface.sls
+++ b/linux/network/interface.sls
@@ -225,10 +225,20 @@
 
 linux_interface_ipflush_onchange_{{ interface_name }}:
   cmd.run:
-  - name: "/sbin/ip address flush dev {{ interface_name }}; ifdown {{ interface_name }} ;ifup {{ interface_name }};"
+  - name: "/sbin/ip address flush dev {{ interface_name }}"
   - onchanges:
     - network: linux_interface_{{ interface_name }}
 
+{%- if interface.get('restart_on_ipflush', False) %}
+
+linux_interface_restart_on_ipflush_{{ interface_name }}:
+  cmd.run:
+  - name: "ifdown {{ interface_name }}; ifup {{ interface_name }};"
+  - onchanges:
+    - cmd: linux_interface_ipflush_onchange_{{ interface_name }}
+
+{%- endif %}
+
 {%- endif %}
 
 {%- if salt['grains.get']('saltversion') < '2017.7' %}
diff --git a/linux/storage/lvm.sls b/linux/storage/lvm.sls
index e88c2f1..2a0a67c 100644
--- a/linux/storage/lvm.sls
+++ b/linux/storage/lvm.sls
@@ -5,6 +5,23 @@
   pkg.installed:
   - pkgs: {{ storage.lvm_pkgs }}
 
+
+/etc/lvm/lvm.conf:
+  file.managed:
+  - source: salt://linux/files/lvm.conf
+  - template: jinja
+  - require:
+    - pkg: linux_lvm_pkgs
+
+lvm_services:
+  service.running:
+  - enable: true
+  - names: {{ storage.lvm_services }}
+  - require:
+    - file: /etc/lvm/lvm.conf
+  - watch:
+    - file: /etc/lvm/lvm.conf
+
 {%- for vgname, vg in storage.lvm.iteritems() %}
 
 {%- if vg.get('enabled', True) %}
@@ -15,6 +32,8 @@
     - name: {{ dev }}
     - require:
       - pkg: linux_lvm_pkgs
+      - file: /etc/lvm/lvm.conf
+      - service: lvm_services
     - require_in:
       - lvm: lvm_vg_{{ vg.get('name', vgname) }}
 {%- endfor %}
@@ -47,20 +66,4 @@
 
 {%- endfor %}
 
-/etc/lvm/lvm.conf:
-  file.managed:
-  - source: salt://linux/files/lvm.conf
-  - template: jinja
-  - require:
-    - pkg: linux_lvm_pkgs
-
-lvm_services:
-  service.running:
-  - enable: true
-  - names: {{ storage.lvm_services }}
-  - require:
-    - file: /etc/lvm/lvm.conf
-  - watch:
-    - file: /etc/lvm/lvm.conf
-
-{%- endif %}
+{%- endif %}
\ No newline at end of file
diff --git a/linux/system/cgroup.sls b/linux/system/cgroup.sls
new file mode 100644
index 0000000..caac31c
--- /dev/null
+++ b/linux/system/cgroup.sls
@@ -0,0 +1,119 @@
+{%- from "linux/map.jinja" import system with context %}
+
+{%- if system.cgroup.enabled|default(True) %}
+
+cgroup_package:
+  pkg.installed:
+  - pkgs:
+    - cgroup-bin
+
+include:
+  - linux.system.grub
+
+/etc/default/grub.d/80-cgroup.cfg:
+  file.managed:
+  - contents: 'GRUB_CMDLINE_LINUX_DEFAULT="quiet cgroup_enable=memory swapaccount=1"'
+  - require:
+    - file: grub_d_directory
+{%- if grains.get('virtual_subtype', None) not in ['Docker', 'LXC'] %}
+  - watch_in:
+    - cmd: grub_update
+{%- endif %}
+
+/etc/cgconfig.conf:
+  file.managed:
+  - user: root
+  - group: root
+  - mode: 0644
+  - template: jinja
+  - source: salt://linux/files/cgconfig.conf
+{%- if grains.get('virtual_subtype', None) not in ['Docker', 'LXC'] %}
+  - check_cmd: /usr/sbin/cgconfigparser -l
+{%- endif %}
+
+/etc/cgrules.conf:
+  file.managed:
+  - user: root
+  - group: root
+  - mode: 0644
+  - template: jinja
+  - source: salt://linux/files/cgrules.conf
+
+/etc/default/cgred:
+  file.managed:
+  - contents: |
+      OPTIONS=-v --logfile=/var/log/cgrulesengd.log
+
+/etc/systemd/system/cgred.service:
+  file.managed:
+  - contents: |
+      [Unit]
+      Description=CGroups Rules Engine Daemon
+      After=syslog.target
+
+      [Service]
+      Type=forking
+      EnvironmentFile=-/etc/default/cgred
+      ExecStart=/usr/sbin/cgrulesengd $OPTIONS
+
+      [Install]
+      WantedBy=multi-user.target
+
+cgred_service_running:
+  service.running:
+  - enable: true
+  - names: ['cgred']
+  - watch:
+    - file: /etc/cgconfig.conf
+    - file: /etc/cgrules.conf
+    - file: /etc/default/cgred
+    - file: /etc/systemd/system/cgred.service
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
+
+{%- else %}
+
+cgred_service_dead:
+  service.dead:
+  - enable: false
+  - names: ['cgred']
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
+
+include:
+  - linux.system.grub
+
+remove_/etc/default/grub.d/80-cgroup.cfg:
+  file.absent:
+  - name: /etc/default/grub.d/80-cgroup.cfg
+  - require:
+    - file: grub_d_directory
+{%- if grains.get('virtual_subtype', None) not in ['Docker', 'LXC'] %}
+  - watch_in:
+    - cmd: grub_update
+{%- endif %}
+
+remove_/etc/systemd/system/cgred.service:
+  file.absent:
+  - name: /etc/systemd/system/cgred.service
+
+remove_/etc/cgconfig.conf:
+  file.absent:
+  - name: /etc/cgconfig.conf
+
+remove_/etc/cgrules.conf:
+  file.absent:
+  - name: /etc/cgrules.conf
+
+remove_/etc/default/cgred:
+  file.absent:
+  - name: /etc/default/cgred
+
+purge_cgroup_package:
+  pkg.purged:
+  - pkgs:
+    - cgroup-tools
+
+{%- endif %}
diff --git a/linux/system/init.sls b/linux/system/init.sls
index e17adc5..af61698 100644
--- a/linux/system/init.sls
+++ b/linux/system/init.sls
@@ -33,6 +33,9 @@
 {%- if system.sysfs is defined %}
 - linux.system.sysfs
 {%- endif %}
+{%- if system.cgroup is defined %}
+- linux.system.cgroup
+{%- endif %}
 {%- if system.locale|length > 0 %}
 - linux.system.locale
 {%- endif %}
@@ -99,6 +102,9 @@
 {%- if system.directory is defined %}
 - linux.system.directory
 {%- endif %}
+{%- if system.ld is defined %}
+- linux.system.ld
+{%- endif %}
 {%- if system.apt is defined and grains.os_family == 'Debian' %}
 - linux.system.apt
 {%- endif %}
diff --git a/linux/system/ld.sls b/linux/system/ld.sls
new file mode 100644
index 0000000..fb239da
--- /dev/null
+++ b/linux/system/ld.sls
@@ -0,0 +1,23 @@
+{%- from "linux/map.jinja" import system with context %}
+
+{%- if system.enabled %}
+
+{%- for key in system.ld.library %}
+/etc/ld.so.conf.d/{{ key }}.conf:
+  file.managed:
+    - user: root
+    - group: root
+    - mode: 644
+    - contents: |
+          {% for val in system.ld.library[key] -%}
+          {{ val }}
+          {% endfor %}
+    - watch_in:
+      - cmd: ldconfig_update
+{% endfor %}
+
+ldconfig_update:
+  cmd.wait:
+  - name: ldconfig
+
+{% endif %}
diff --git a/linux/system/repo.sls b/linux/system/repo.sls
index 1ea921c..aa646ef 100644
--- a/linux/system/repo.sls
+++ b/linux/system/repo.sls
@@ -108,7 +108,7 @@
   {%- if repo.ppa is defined %}
   - ppa: {{ repo.ppa }}
   {%- else %}
-  - human_name: {{ name }}
+  - humanname: {{ name }}
   - name: {{ repo.source }}
   {%- if repo.architectures is defined %}
   - architectures: {{ repo.architectures }}
@@ -143,6 +143,19 @@
 {%- else %}
 
 linux_repo_{{ name }}_absent:
+  pkgrepo.absent:
+    {%- if repo.ppa is defined %}
+    - ppa: {{ repo.ppa }}
+    {%- if repo.key_id is defined %}
+    - keyid_ppa: {{ repo.keyid_ppa }}
+    {%- endif %}
+    {%- else %}
+    - name: {{ repo.source }}
+    - file: /etc/apt/sources.list.d/{{ name }}.list
+    {%- if repo.key_id is defined %}
+    - keyid: {{ repo.key_id }}
+    {%- endif %}
+    {%- endif %}
   file.absent:
     - name: /etc/apt/sources.list.d/{{ name }}.list
 
@@ -150,17 +163,19 @@
 
 {%- endif %}
 
+{#- os_family Debian #}
 {%- endif %}
 
 {%- if grains.os_family == "RedHat" %}
 
+{%- if repo.get('enabled', True) %}
+
 {%- if repo.get('proxy', {}).get('enabled', False) %}
 # PLACEHOLDER
 # TODO, implement per proxy configuration for Yum
 {%- endif %}
 
 {%- if not repo.get('default', False) %}
-
 linux_repo_{{ name }}:
   pkgrepo.managed:
   - name: {{ name }}
@@ -176,11 +191,18 @@
   {%- endif %}
   - require:
     - pkg: linux_repo_prereq_pkgs
-
 {%- endif %}
 
+{#- repo.enabled is false #}
+{%- else %}
+  pkgrepo.absent:
+    - name: {{ repo.source }}
 {%- endif %}
 
+{#- os_family Redhat #}
+{%- endif %}
+
+{#- repo.iteritems() loop #}
 {%- endfor %}
 
 {%- if default_repos|length > 0 and grains.os_family == 'Debian' %}
diff --git a/tests/pillar/system.sls b/tests/pillar/system.sls
index 06a1bdc..497aee2 100644
--- a/tests/pillar/system.sls
+++ b/tests/pillar/system.sls
@@ -19,6 +19,16 @@
     kernel:
       isolcpu: 1,2,3,4
       elevator: deadline
+    cgroup:
+      group:
+        group_1:
+          controller:
+            cpu:
+              shares:
+                value: 250
+          mapping:
+            subjects:
+            - '@group1'
     sysfs:
       scheduler:
         block/sda/queue/scheduler: deadline