Initial commit
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
new file mode 100644
index 0000000..9299a80
--- /dev/null
+++ b/CHANGELOG.rst
@@ -0,0 +1,6 @@
+linux-formula
+=============
+
+0.0.1 (2015-08-03)
+
+- Initial formula setup
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8e80b12
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2014-2015 tcp cloud a. s.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..1bd6f32
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,357 @@
+
+=====
+Linux
+=====
+
+Linux Operating Systems.
+
+* Ubuntu
+* CentOS
+* RedHat
+* Fedora
+* Arch
+
+Sample pillars
+==============
+
+Linux system
+------------
+
+Basic Linux box
+
+.. code-block:: yaml
+
+    linux:
+      system:
+        enabled: true
+        name: 'node1'
+        domain: 'domain.com'
+        cluster: 'system'
+        environment: prod
+        timezone: 'Europe/Prague'
+        utc: true
+
+Linux with system users, sowe with password set
+
+.. code-block:: yaml
+
+    linux:
+      system:
+        ...
+        user:
+          jdoe:
+            name: 'jdoe'
+            enabled: true
+            sudo: true
+            shell: /bin/bash
+            full_name: 'Jonh Doe'
+            home: '/home/jdoe'
+            email: 'jonh@doe.com'
+          jsmith:
+            name: 'jsmith'
+            enabled: true
+            full_name: 'Password'
+            home: '/home/jsmith'
+            password: userpassword
+
+Linux with package, latest version
+
+.. code-block:: yaml
+
+    linux:
+      system:
+        ...
+        package:
+          package-name:
+            version: latest
+
+Linux with package from certail repo, version with no upgrades
+
+.. code-block:: yaml
+
+    linux:
+      system:
+        ...
+        package:
+          package-name:
+            version: 2132.323
+            repo: 'custom-repo'
+            hold: true
+
+Linux with package from certail repo, version with no GPG verification
+
+.. code-block:: yaml
+
+    linux:
+      system:
+        ...
+        package:
+          package-name:
+            version: 2132.323
+            repo: 'custom-repo'
+            verify: false
+
+Linux with cron jobs
+
+.. code-block:: yaml
+
+    linux:
+      system:
+        ...
+        job:
+          cmd1:
+            command: '/cmd/to/run'
+            enabled: true
+            user: 'root'
+            hour: 2
+            minute: 0
+
+Repositories
+~~~~~~~~~~~~
+
+RedHat based Linux with additional OpenStack repo
+
+.. code-block:: yaml
+
+    linux:
+      system:
+        ...
+        repo:
+          rdo-icehouse:
+            enabled: true
+            source: 'http://repos.fedorapeople.org/repos/openstack/openstack-icehouse/epel-6/'
+            pgpcheck: 0
+
+Ensure system repository to use czech Debian mirror (``default: true``)
+Also pin it's packages with priority 900.
+
+.. code-block:: yaml
+
+   linux:
+     system:
+       repo:
+         debian:
+           default: true
+           source: "deb http://ftp.cz.debian.org/debian/ jessie main contrib non-free"
+           # Import signing key from URL if needed
+           key_url: "http://dummy.com/public.gpg"
+           pin:
+             - pin: 'origin "ftp.cz.debian.org"'
+               priority: 900
+               package: '*'
+
+Linux network
+-------------
+
+Linux with network manager
+
+.. code-block:: yaml
+
+    linux:
+      network:
+        enabled: true
+        network_manager: true
+
+Linux with default static network interfaces, default gateway interface and DNS servers
+
+.. code-block:: yaml
+
+    linux:
+      network:
+        enabled: true
+        interface:
+          eth0:
+            enabled: true
+            type: eth
+            address: 192.168.0.102
+            netmask: 255.255.255.0
+            gateway: 192.168.0.1
+            name_servers:
+            - 8.8.8.8
+            - 8.8.4.4
+            mtu: 1500
+
+Linux with bonded interfaces
+
+.. code-block:: yaml
+
+    linux:
+      network:
+        enabled: true
+        interface:
+          eth0:
+            type: eth
+            ...
+          eth1:
+            type: eth
+            ...
+          bond0:
+            enabled: true
+            type: bond
+            address: 192.168.0.102
+            netmask: 255.255.255.0
+            mtu: 1500
+            use_in:
+            - interface: ${linux:interface:eth0}
+            - interface: ${linux:interface:eth0}
+
+Linux with wireless interface parameters
+
+.. code-block:: yaml
+
+    linux:
+      network:
+        enabled: true
+        gateway: 10.0.0.1
+        default_interface: eth0 
+        interface:
+          wlan0:
+            type: eth
+            wireless:
+              essid: example
+              key: example_key
+              security: wpa
+              priority: 1
+
+Linux networks with routes defined
+
+.. code-block:: yaml
+
+    linux:
+      network:
+        enabled: true
+        gateway: 10.0.0.1
+        default_interface: eth0 
+        interface:
+          eth0:
+            type: eth
+            route:
+              default:
+                address: 192.168.0.123
+                netmask: 255.255.255.0
+                gateway: 192.168.0.1
+
+Native Linux Bridges
+
+.. code-block:: yaml
+
+    linux:
+      network:
+        interface:
+          eth1:
+            enabled: true
+            type: eth
+            proto: manual
+            up_cmds:
+            - ip address add 0/0 dev $IFACE
+            - ip link set $IFACE up
+            down_cmds:
+            - ip link set $IFACE down
+          br-ex:
+            enabled: true
+            type: bridge
+            address: ${linux:network:host:public_local:address}
+            netmask: 255.255.255.0
+            use_interfaces:
+            - eth1
+
+OpenVswitch Bridges
+
+.. code-block:: yaml
+
+    linux:
+      network:
+        bridge: openvswitch
+        interface:
+          eth1:
+            enabled: true
+            type: eth
+            proto: manual
+            up_cmds:
+            - ip address add 0/0 dev $IFACE
+            - ip link set $IFACE up
+            down_cmds:
+            - ip link set $IFACE down
+          br-ex:
+            enabled: true
+            type: bridge
+            address: ${linux:network:host:public_local:address}
+            netmask: 255.255.255.0
+            use_interfaces:
+            - eth1
+
+Linux with proxy
+
+.. code-block:: yaml
+
+    linux:
+      network:
+        ...
+        proxy:
+          host: proxy.domain.com
+          port: 3128
+
+Linux with hosts
+
+.. code-block:: yaml
+
+    linux:
+      network:
+        ...
+        host:
+          node1:
+            address: 192.168.10.200
+            names:
+            - node2.domain.com
+            - service2.domain.com
+          node2:
+            address: 192.168.10.201
+            names:
+            - node2.domain.com
+            - service2.domain.com
+
+Linux storage pillars
+---------------------
+
+Linux with mounted Samba
+
+.. code-block:: yaml
+
+    linux:
+      storage:
+        enabled: true
+        mount:
+          samba1:
+          - path: /media/myuser/public/
+          - device: //192.168.0.1/storage
+          - file_system: cifs
+          - options: guest,uid=myuser,iocharset=utf8,file_mode=0777,dir_mode=0777,noperm
+
+Linux with file swap
+
+.. code-block:: yaml
+
+    linux:
+      storage:
+        enabled: true
+        swap:
+          file:
+            enabled: true
+            engine: file
+            device: /swapfile
+            size: 1024
+
+Usage
+=====
+
+Set mtu of network interface eth0 to 1400
+
+.. code-block:: bash
+
+    ip link set dev eth0 mtu 1400
+
+Read more
+=========
+
+* https://www.archlinux.org/
+* http://askubuntu.com/questions/175172/how-do-i-configure-proxies-in-ubuntu-server-or-minimal-cli-ubuntu
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..3b04cfb
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.2
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..f992752
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,11 @@
+salt-formula-linux (0.2) trusty; urgency=medium
+
+  * First public release
+
+ -- Filip Pytloun <filip.pytloun@tcpcloud.eu>  Tue, 06 Oct 2015 16:38:46 +0200
+
+salt-formula-linux (0.1) trusty; urgency=medium
+
+  * Initial release
+
+ -- Ales Komarek <ales.komarek@tcpcloud.eu>  Thu, 13 Aug 2015 23:23:41 +0200
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..ce2b461
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,15 @@
+Source: salt-formula-linux
+Maintainer: Ales Komarek <ales.komarek@tcpcloud.eu>
+Section: admin
+Priority: optional
+Build-Depends: debhelper (>= 9)
+Standards-Version: 3.9.6
+Homepage: http://www.tcpcloud.eu
+Vcs-Browser: https://github.com/tcpcloud/salt-formula-linux
+Vcs-Git: https://github.com/tcpcloud/salt-formula-linux.git
+
+Package: salt-formula-linux
+Architecture: all
+Depends: ${misc:Depends}, salt-master, reclass
+Description: Linux salt formula
+ Configure Linux operating system.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..22bb6ee
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,15 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: salt-formula-linux
+Upstream-Contact: Ales Komarek <ales.komarek@tcpcloud.eu>
+Source: https://github.com/tcpcloud/salt-formula-linux
+
+Files: *
+Copyright: 2014-2015 tcp cloud a.s.
+License: Apache-2.0
+  Copyright (C) 2014-2015 tcp cloud a.s.
+  .
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  .
+  On a Debian system you can find a copy of this license in
+  /usr/share/common-licenses/Apache-2.0.
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..d585829
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1,3 @@
+README.rst
+CHANGELOG.rst
+VERSION
diff --git a/debian/install b/debian/install
new file mode 100644
index 0000000..aaeeacc
--- /dev/null
+++ b/debian/install
@@ -0,0 +1,2 @@
+linux/*             /usr/share/salt-formulas/env/linux/
+metadata/service/*      /usr/share/salt-formulas/reclass/service/linux/
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..abde6ef
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,5 @@
+#!/usr/bin/make -f
+
+%:
+	dh $@
+
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..89ae9db
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (native)
diff --git a/linux/files/95proxies b/linux/files/95proxies
new file mode 100644
index 0000000..5bbdaea
--- /dev/null
+++ b/linux/files/95proxies
@@ -0,0 +1,4 @@
+{%- from "linux/map.jinja" import network with context %}
+Acquire::http::proxy "http://{{ network.proxy.host }}:{{ network.proxy.port }}/";
+Acquire::ftp::proxy "ftp://{{ network.proxy.host }}:{{ network.proxy.port }}/";
+Acquire::https::proxy "https://{{ network.proxy.host }}:{{ network.proxy.port }}/";
\ No newline at end of file
diff --git a/linux/files/collectd.conf b/linux/files/collectd.conf
new file mode 100644
index 0000000..02c0101
--- /dev/null
+++ b/linux/files/collectd.conf
@@ -0,0 +1,39 @@
+LoadPlugin cpu
+LoadPlugin df
+LoadPlugin disk
+LoadPlugin entropy
+LoadPlugin interface
+LoadPlugin memory
+LoadPlugin processes
+LoadPlugin swap
+LoadPlugin uptime
+LoadPlugin users
+
+<Plugin df>
+#  Device "/dev/sda1"
+#  Device "192.168.0.2:/mnt/nfs"
+#  MountPoint "/home"
+#  FSType "ext3"
+
+  # ignore rootfs; else, the root file-system would appear twice, causing
+  # one of the updates to fail and spam the log
+  FSType rootfs
+  # ignore the usual virtual / temporary file-systems
+  FSType sysfs
+  FSType proc
+  FSType devtmpfs
+  FSType devpts
+  FSType tmpfs
+  FSType fusectl
+  FSType cgroup
+  IgnoreSelected true
+#  ReportByDevice false
+#  ReportReserved false
+#  ReportInodes false
+</Plugin>
+
+<Plugin disk>
+#  Disk "hda"
+#  Disk "/sda[23]/"
+  IgnoreSelected true
+</Plugin>
diff --git a/linux/files/hostname b/linux/files/hostname
new file mode 100644
index 0000000..b5ec334
--- /dev/null
+++ b/linux/files/hostname
@@ -0,0 +1 @@
+{{ pillar.linux.system.name }}
\ No newline at end of file
diff --git a/linux/files/logstash-filter.conf b/linux/files/logstash-filter.conf
new file mode 100644
index 0000000..acce463
--- /dev/null
+++ b/linux/files/logstash-filter.conf
@@ -0,0 +1,13 @@
+filter {
+  if [type] == "syslog" {
+    grok {
+      match => { "message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" }
+      add_field => [ "received_at", "%{@timestamp}" ]
+      add_field => [ "received_from", "%{host}" ]
+    }
+    syslog_pri { }
+    date {
+      match => [ "syslog_timestamp", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
+    }
+  }
+}
diff --git a/linux/files/logstash-forwarder.conf b/linux/files/logstash-forwarder.conf
new file mode 100644
index 0000000..660093b
--- /dev/null
+++ b/linux/files/logstash-forwarder.conf
@@ -0,0 +1,7 @@
+{
+  "paths": [
+    "/var/log/syslog",
+    "/var/log/auth.log"
+   ],
+  "fields": { "type": "syslog" }
+}
diff --git a/linux/files/multipath.conf b/linux/files/multipath.conf
new file mode 100644
index 0000000..3d8cce7
--- /dev/null
+++ b/linux/files/multipath.conf
@@ -0,0 +1,98 @@
+{%- from "linux/map.jinja" import storage with context %}
+##
+## This is a template multipath-tools configuration file
+## Uncomment the lines relevent to your environment
+##
+{% set backend = storage.get('backend', 'default') %}
+
+{%- if backend in ['hitachi', 'hds', 'HDS'] %}
+
+defaults {
+#	udev_dir		/dev
+#	polling_interval 	10
+#	selector		"round-robin 0"
+#	path_grouping_policy	multibus
+#	getuid_callout		"/lib/udev/scsi_id --whitelisted --device=/dev/%n"
+#	prio			const
+#	path_checker		directio
+#	rr_min_io		100
+#	flush_on_last_del	no
+#	max_fds			8192
+#	rr_weight		priorities
+#	failback		immediate
+#	no_path_retry		fail
+#	queue_without_daemon    no
+	user_friendly_names	no
+#	mode			644
+#	uid			0
+#	gid			disk
+}
+
+{%- elif backend in ['fujitsu'] %}
+defaults {
+                user_friendly_names no
+}
+blacklist {
+        wwid "355cd2e404b76b*"
+}
+devices {
+         device {
+                 vendor                  "FUJITSU"
+                 product                 "ETERNUS_DXL"
+                 prio                    alua
+                 path_grouping_policy    group_by_prio
+                 path_selector           "round-robin 0"
+                 failback                immediate
+                 no_path_retry           0
+                 path_checker            tur
+                 dev_loss_tmo            2097151
+                 fast_io_fail_tmo        1
+          }
+}
+
+{%- else %}
+
+defaults {
+	getuid_callout		"/lib/udev/scsi_id --whitelisted --device=/dev/%n"
+	user_friendly_names	no
+}
+
+blacklist {
+#       wwid 26353900f02796769
+#	devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
+#	devnode "^hd[a-z][[0-9]*]"
+#	device {
+#		vendor DEC.*
+#		product MSA[15]00
+#	}
+        #
+        #  POZOR - filtrace vseho krome blacklistovanych veci
+        #
+#        wwid "*"
+}
+blacklist_exceptions {
+#       devnode "^dasd[c-d]+[0-9]*"
+#       wwid    "IBM.75000000092461.4d00.34"
+#	wwid	3600507680280050cd000000000000035
+#	wwid	3600507680280050cd000000000000030
+#	wwid	3600507680280050cd0000000000000ac
+#	wwid	3600507680280050cd0000000000003df
+	wwid "*"
+}
+devices {
+	device {
+		vendor "IBM"
+		product "2145"
+		path_grouping_policy group_by_prio
+		getuid_callout "/lib/udev/scsi_id --whitelisted --device=/dev/%n"
+		features "1 queue_if_no_path"
+		prio alua
+		path_checker tur
+		failback immediate
+		no_path_retry "5"
+		rr_min_io 1
+ 		polling_interval 30
+		dev_loss_tmo 120
+	}
+}
+{%- endif %}
diff --git a/linux/files/multipath.conf.hds b/linux/files/multipath.conf.hds
new file mode 100644
index 0000000..0bc246f
--- /dev/null
+++ b/linux/files/multipath.conf.hds
@@ -0,0 +1,24 @@
+##
+## This is a template multipath-tools configuration file
+## Uncomment the lines relevent to your environment
+##
+defaults {
+#	udev_dir		/dev
+#	polling_interval 	10
+#	selector		"round-robin 0"
+#	path_grouping_policy	multibus
+#	getuid_callout		"/lib/udev/scsi_id --whitelisted --device=/dev/%n"
+#	prio			const
+#	path_checker		directio
+#	rr_min_io		100
+#	flush_on_last_del	no
+#	max_fds			8192
+#	rr_weight		priorities
+#	failback		immediate
+#	no_path_retry		fail
+#	queue_without_daemon    no
+	user_friendly_names	no
+#	mode			644
+#	uid			0
+#	gid			disk
+}
diff --git a/linux/files/preferences_repo b/linux/files/preferences_repo
new file mode 100644
index 0000000..603d313
--- /dev/null
+++ b/linux/files/preferences_repo
@@ -0,0 +1,8 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- set repo = system.repo[repo_name] %}
+{%- for pin in repo.pin %}
+{%- set package = pin.get('package', '*') %}
+Package: {{ package }}
+Pin: {{ pin.pin }}
+Pin-Priority: {{ pin.priority }}
+{% endfor %}
diff --git a/linux/files/proxy.sh b/linux/files/proxy.sh
new file mode 100644
index 0000000..f2dc031
--- /dev/null
+++ b/linux/files/proxy.sh
@@ -0,0 +1,9 @@
+{%- from "linux/map.jinja" import network with context %}
+export http_proxy="http://{{ network.proxy.host }}:{{ network.proxy.port }}/"
+export https_proxy="http://{{ network.proxy.host }}:{{ network.proxy.port }}/"
+export ftp_proxy="http://{{ network.proxy.host }}:{{ network.proxy.port }}/"
+export no_proxy="localhost,127.0.0.1,localaddress,.localdomain.com"
+export HTTP_PROXY="http://{{ network.proxy.host }}:{{ network.proxy.port }}/"
+export HTTPS_PROXY="http://{{ network.proxy.host }}:{{ network.proxy.port }}/"
+export FTP_PROXY="http://{{ network.proxy.host }}:{{ network.proxy.port }}/"
+export NO_PROXY="localhost,127.0.0.1,localaddress,.localdomain.com"
\ No newline at end of file
diff --git a/linux/files/sensu.conf b/linux/files/sensu.conf
new file mode 100644
index 0000000..460bce7
--- /dev/null
+++ b/linux/files/sensu.conf
@@ -0,0 +1,36 @@
+local_linux_system_zombie_procs:
+  command: "PATH=$PATH:/usr/lib64/nagios/plugins:/usr/lib/nagios/plugins check_procs -w 1 -c 5 -s Z"
+  interval: 60
+  occurrences: 3
+  subscribers:
+  - local-linux-system
+local_linux_system_total_procs:
+  command: "PATH=$PATH:/usr/lib64/nagios/plugins:/usr/lib/nagios/plugins check_procs -w 1500 -c 3000"
+  interval: 60
+  occurrences: 5
+  subscribers:
+  - local-linux-system
+local_linux_system_load:
+  command: "PATH=$PATH:/usr/lib64/nagios/plugins:/usr/lib/nagios/plugins check_load -r -w 6,4,2 -c 12,8,4"
+  interval: 60
+  occurrences: 1
+  subscribers:
+  - local-linux-system
+local_linux_storage_swap_usage:
+  command: "PATH=$PATH:/usr/lib64/nagios/plugins:/usr/lib/nagios/plugins check_swap -a -w 50% -c 20%"
+  interval: 60
+  occurrences: 1
+  subscribers:
+  - local-linux-storage
+local_linux_storage_disk_usage:
+  command: "PATH=$PATH:/usr/lib64/nagios/plugins:/usr/lib/nagios/plugins check_disk -w 15% -c 5% -p / -p /var -p /usr -p /tmp -p /var/log"
+  interval: 60
+  occurrences: 1
+  subscribers:
+  - local-linux-storage
+local_linux_network_fqdn:
+  command: "PATH=$PATH:/etc/sensu/plugins check_fqdn.py -n :::hostname::: -f :::fqdn:::"
+  interval: 60
+  occurrences: 1
+  subscribers:
+  - local-linux-network
diff --git a/linux/files/sources.list b/linux/files/sources.list
new file mode 100644
index 0000000..ed41e7b
--- /dev/null
+++ b/linux/files/sources.list
@@ -0,0 +1,4 @@
+{%- for name, repo in default_repos.iteritems() %}
+# Repository {{ name }}
+{{ repo.source }}
+{%- endfor %}
diff --git a/linux/files/sudoer b/linux/files/sudoer
new file mode 100644
index 0000000..3b682af
--- /dev/null
+++ b/linux/files/sudoer
@@ -0,0 +1,5 @@
+# managed by salt
+
+# user {{ user_name }} is system administrator.
+# It has passwordless sudo functionality.
+{{ user_name }} ALL=(ALL) NOPASSWD:ALL
diff --git a/linux/files/wireless b/linux/files/wireless
new file mode 100644
index 0000000..4ae91f9
--- /dev/null
+++ b/linux/files/wireless
@@ -0,0 +1,8 @@
+{%- set interface = salt['pillar.get']('linux:network:interface:'+interface_name) %}
+Interface={{ interface_name }}
+Connection=wireless
+Security={{ interface.wireless.security }}
+ESSID={{ interface.wireless.essid }}
+IP=dhcp
+Key={{ interface.wireless.key }}
+Priority={{ interface.wireless.get('priority', '1') }}
diff --git a/linux/init.sls b/linux/init.sls
new file mode 100644
index 0000000..1fdc5ed
--- /dev/null
+++ b/linux/init.sls
@@ -0,0 +1,12 @@
+{%- if pillar.linux is defined %}
+include:
+{%- if pillar.linux.system is defined %}
+- linux.system
+{%- endif %}
+{%- if pillar.linux.network is defined %}
+- linux.network
+{%- endif %}
+{%- if pillar.linux.storage is defined %}
+- linux.storage
+{%- endif %}
+{%- endif %}
\ No newline at end of file
diff --git a/linux/map.jinja b/linux/map.jinja
new file mode 100644
index 0000000..66dbce0
--- /dev/null
+++ b/linux/map.jinja
@@ -0,0 +1,117 @@
+{% set system = salt['grains.filter_by']({
+    'Arch': {
+        'pkgs': ['sudo', 'vim', 'wget'],
+        'utc': true,
+        'user': {},
+        'group': {},
+        'job': {},
+        'repo': {},
+        'package': {},
+        'selinux': 'permissive',
+        'ca_certs_dir': '/usr/local/share/ca-certificates',
+    },
+    'Debian': {
+        'pkgs': ['python-apt','vim'],
+        'utc': true,
+        'user': {},
+        'group': {},
+        'job': {},
+        'repo': {},
+        'package': {},
+        'selinux': 'permissive',
+        'ca_certs_dir': '/usr/local/share/ca-certificates',
+    },
+    'RedHat': {
+        'pkgs': ['policycoreutils', 'policycoreutils-python', 'vim-enhanced', 'telnet', 'wget'],
+        'utc': true,
+        'user': {},
+        'group': {},
+        'job': {},
+        'repo': {},
+        'package': {},
+        'selinux': 'permissive',
+        'ca_certs_dir': '/usr/local/share/ca-certificates',
+    },
+}, grain='os_family', merge=salt['pillar.get']('linux:system')) %}
+
+{#    'network_name', #}
+
+{% set interface_params = [
+    'gateway',
+    'mtu',
+    'network',
+    'broadcast',
+    'master',
+    'miimon',
+    'mode',
+    'lacp-rate',
+    'dns-search',
+    'up_cmds',
+    'pre_up_cmds',
+    'post_up_cmds',
+    'down_cmds',
+    'pre_down_cmds',
+    'post_down_cmds',
+] %}
+
+{% set network = salt['grains.filter_by']({
+    'Arch': {
+        'pkgs': ['wpa_supplicant', 'dhclient', 'wireless_tools'],
+        'bridge_pkgs': ['bridge-utils'],
+        'ovs_pkgs': ['openvswitch-switch'],
+        'hostname_file': '/etc/hostname',
+        'network_manager': False,
+        'interface': {},
+        'interface_params': interface_params,
+        'bridge': 'none',
+        'proxy': {
+           'host': 'none',
+        },
+        'host': {},
+    },
+    'Debian': {
+        'hostname_file': '/etc/hostname',
+        'bridge_pkgs': ['bridge-utils'],
+        'ovs_pkgs': ['openvswitch-switch'],
+        'network_manager': False,
+        'interface': {},
+        'interface_params': interface_params,
+        'bridge': 'none',
+        'proxy': {
+           'host': 'none',
+        },
+        'host': {},
+    },
+    'RedHat': {
+        'bridge_pkgs': ['bridge-utils'],
+        'ovs_pkgs': ['openvswitch-switch'],
+        'hostname_file': '/etc/sysconfig/network',
+        'network_manager': False,
+        'interface': {},
+        'interface_params': interface_params,
+        'bridge': 'none',
+        'proxy': {
+           'host': 'none',
+        },
+        'host': {},
+    },
+}, grain='os_family', merge=salt['pillar.get']('linux:network')) %}
+
+{% set storage = salt['grains.filter_by']({
+    'Arch': {
+        'mount': {},
+        'swap': {},
+        'multipath': False,
+    },
+    'Debian': {
+        'mount': {},
+        'swap': {},
+        'multipath': False,
+        'multipath_pkgs': ['multipath-tools']
+    },
+    'RedHat': {
+        'mount': {},
+        'swap': {},
+        'multipath': False,
+    },
+}, grain='os_family', merge=salt['pillar.get']('linux:storage')) %}
diff --git a/linux/network/host.sls b/linux/network/host.sls
new file mode 100644
index 0000000..8254f4f
--- /dev/null
+++ b/linux/network/host.sls
@@ -0,0 +1,17 @@
+{%- from "linux/map.jinja" import network with context %}
+{%- if network.enabled %}
+
+{%- for name, host in network.host.iteritems() %}
+
+{%- if host.names is defined %}
+
+linux_host_{{ name }}:
+  host.present:
+  - ip: {{ host.address }}
+  - names: {{ host.names }}
+
+{%- endif %}
+
+{%- endfor %}
+
+{%- endif %}
\ No newline at end of file
diff --git a/linux/network/hostname.sls b/linux/network/hostname.sls
new file mode 100644
index 0000000..7c1594a
--- /dev/null
+++ b/linux/network/hostname.sls
@@ -0,0 +1,32 @@
+{%- from "linux/map.jinja" import network with context %}
+{%- if network.enabled %}
+
+{%- if grains.os_family in ['Arch', 'Debian'] %}
+
+linux_hostname_file:
+  file.managed:
+  - name: {{ network.hostname_file }}
+  - source: salt://linux/files/hostname
+  - template: jinja
+  - user: root
+  - group: root
+  - mode: 644
+  - watch_in:
+    - cmd: linux_enforce_hostname
+
+{%- endif %}
+
+linux_enforce_hostname:
+  cmd.wait:
+  - name: hostname {{ network.hostname }}
+
+{#
+linux_hostname_hosts:
+  host.present:
+  - ip: {{ grains.ip4_interfaces[network.get('default_interface', 'eth0')][0] }}
+  - names:
+    - {{ network.fqdn }}
+    - {{ network.hostname }}
+#}
+
+{%- endif %}
\ No newline at end of file
diff --git a/linux/network/init.sls b/linux/network/init.sls
new file mode 100644
index 0000000..2238cdd
--- /dev/null
+++ b/linux/network/init.sls
@@ -0,0 +1,10 @@
+{%- from "linux/map.jinja" import network with context %}
+include:
+- linux.network.hostname
+{%- if network.host|length > 0 %}
+- linux.network.host
+{%- endif %}
+{%- if network.interface|length > 0 %}
+- linux.network.interface
+{%- endif %}
+- linux.network.proxy
diff --git a/linux/network/interface.sls b/linux/network/interface.sls
new file mode 100644
index 0000000..70d7d3d
--- /dev/null
+++ b/linux/network/interface.sls
@@ -0,0 +1,209 @@
+{%- from "linux/map.jinja" import network with context %}
+{%- from "linux/map.jinja" import system with context %}
+{%- if network.enabled %}
+
+{%- macro set_param(param_name, param_dict) -%}
+{%- if param_dict.get(param_name, False) -%}
+- {{ param_name }}: {{ param_dict[param_name] }}
+{%- endif -%}
+{%- endmacro -%}
+
+{%- if network.bridge != 'none' %}
+
+linux_network_bridge_pkgs:
+  pkg.installed:
+  {%- if network.bridge == 'openvswitch' %}
+  - names: {{ network.ovs_pkgs }}
+  {%- else %}
+  - names: {{ network.bridge_pkgs }}
+  {%- endif %}
+
+{%- endif %}
+
+{%- if not network.network_manager %}
+
+{# TODO stop/disable/uninstall network manager #}
+
+{%- for interface_name, interface in network.interface.iteritems() %}
+
+{%- if interface.get('managed', True) %}
+
+{%- if grains.os_family in ['RedHat', 'Debian'] %}
+
+{%- if interface.type == 'bridge' and network.bridge == 'openvswitch' %}
+
+linux_interface_{{ interface_name }}:
+  network.managed:
+  - enabled: {{ interface.enabled }}
+  - name: {{ interface_name }}
+  - type: eth
+  {%- if interface.address is defined %}
+  - proto: {{ interface.get('proto', 'static') }}
+  - ipaddr: {{ interface.address }}
+  - netmask: {{ interface.netmask }}
+  {%- else %}
+  - proto: {{ interface.get('proto', 'dhcp') }}
+  {%- endif %}
+  {%- if interface.name_servers is defined %}
+  - dns: {{ interface.name_servers }}
+  {%- endif %}
+  {%- for param in network.interface_params %}
+  {{ set_param(param, interface) }}
+  {%- endfor %}
+  {%- if interface.wireless is defined and grains.os_family == 'Debian' %}
+  {%- if interface.wireless.security == "wpa" %}
+  - wpa-ssid: {{ interface.wireless.essid }}
+  - wpa-psk: {{ interface.wireless.key }}
+  {%- else %}
+  - wireless-ssid: {{ interface.wireless.essid }}
+  - wireless-psk: {{ interface.wireless.key }}
+  {%- endif %}
+  {%- endif %}
+  - require:
+    - pkg: linux_network_bridge_pkgs
+    {%- for network in interface.use_interfaces %}
+    - network: linux_interface_{{ network }}
+    {%- endfor %}
+
+linux_ovs_bridge_{{ interface_name }}:
+  cmd.run:
+  - name: ovs-vsctl add-br {{ interface_name }}
+  - unless: ovs-vsctl show | grep 'Bridge {{ interface_name }}'
+  - require:
+    - network: linux_interface_{{ interface_name }}
+
+{%- for port in interface.use_interfaces %}
+
+linux_ovs_bridge_{{ interface_name }}_port_{{ port }}:
+  cmd.run:
+  - name: ovs-vsctl add-port {{ interface_name }} {{ port }}
+  - unless: ovs-vsctl show | grep 'Interface "{{ interface_name }}"'
+  - require:
+    - cmd: linux_ovs_bridge_{{ interface_name }}
+
+{%- endfor %}
+
+{%- else %}
+
+linux_interface_{{ interface_name }}:
+  network.managed:
+  - enabled: {{ interface.enabled }}
+  - name: {{ interface_name }}
+  - type: {{ interface.type }}
+  {%- if interface.address is defined %}
+  - proto: {{ interface.get('proto', 'static') }}
+  - ipaddr: {{ interface.address }}
+  - netmask: {{ interface.netmask }}
+  {%- else %}
+  - proto: {{ interface.get('proto', 'dhcp') }}
+  {%- endif %}
+  {%- if interface.name_servers is defined %}
+  - dns: {{ interface.name_servers }}
+  {%- endif %}
+  {%- if interface.wireless is defined and grains.os_family == 'Debian' %}
+  {%- if interface.wireless.security == "wpa" %}
+  - wpa-ssid: {{ interface.wireless.essid }}
+  - wpa-psk: {{ interface.wireless.key }}
+  {%- else %}
+  - wireless-ssid: {{ interface.wireless.essid }}
+  - wireless-psk: {{ interface.wireless.key }}
+  {%- endif %}
+  {%- endif %}
+  {%- for param in network.interface_params %}
+  {{ set_param(param, interface) }}
+  {%- endfor %}
+  {%- if interface.type == 'bridge' %}
+  - bridge: {{ interface_name }}
+  - delay: 0
+  - bypassfirewall: True
+  - use:
+    {%- for network in interface.use_interfaces %}
+    - network: {{ network }}
+    {%- endfor %}
+  - ports: {% for network in interface.use_interfaces %}{{ network }} {% endfor %}
+  - require:
+    {%- for network in interface.use_interfaces %}
+    - network: linux_interface_{{ network }}
+    {%- endfor %}
+  {%- endif %}
+
+{%- if interface.gateway is defined %}
+
+linux_system_network:
+  network.system:
+  - enabled: {{ interface.enabled }}
+  - hostname: {{ network.fqdn }}
+  {%- if interface.gateway is defined %}
+  - gateway: {{ interface.gateway }}
+  - gatewaydev: {{ interface_name }}
+  {%- endif %}
+  - nozeroconf: True
+  - nisdomain: {{ system.domain }}
+  - require_reboot: False
+
+{%- endif %}
+
+{%- endif %}
+
+{%- endif %}
+
+{%- if interface.wireless is defined %}
+
+{%- if grains.os_family == 'Arch' %}
+
+linux_network_packages:
+  pkg.installed:
+  - names: {{ network.pkgs }}
+
+/etc/netctl/network_{{ interface.wireless.essid }}:
+  file.managed:
+  - source: salt://linux/files/wireless
+  - mode: 755
+  - template: jinja
+  - require:
+    - pkg: linux_network_packages
+  - defaults:
+      interface_name: {{ interface_name }}
+
+switch_profile_{{ interface.wireless.essid }}:
+  cmd.run:
+    - name: netctl switch-to network_{{ interface.wireless.essid }}
+    - cwd: /root
+    - unless: "iwconfig {{ interface_name }} | grep -e 'ESSID:\"{{ interface.wireless.essid }}\"'"
+    - require:
+      - file: /etc/netctl/network_{{ interface.wireless.essid }}
+
+enable_profile_{{ interface.wireless.essid }}:
+  cmd.run:
+    - name: netctl enable network_{{ interface.wireless.essid }}
+    - cwd: /root
+    - unless: test -e /etc/systemd/system/multi-user.target.wants/netctl@network_{{ interface.wireless.essid }}.service
+    - require:
+      - file: /etc/netctl/network_{{ interface.wireless.essid }}
+
+{%- endif %}
+
+{%- endif %}
+
+{%- endif %}
+
+{%- if interface.route is defined %}
+
+linux_network_{{ interface_name }}_routes:
+  network.routes:
+  - name: {{ interface_name }}
+  - routes:
+    {%- for route_name, route in interface.route.iteritems() %}
+    - name: {{ route_name }}
+      ipaddr: {{ route.address }}
+      netmask: {{ route.netmask }}
+      gateway: {{ route.gateway }}
+    {%- endfor %}
+
+{%- endif %}
+
+{%- endfor %}
+
+{%- endif %}
+
+{%- endif %}
diff --git a/linux/network/proxy.sls b/linux/network/proxy.sls
new file mode 100644
index 0000000..ccfaa9a
--- /dev/null
+++ b/linux/network/proxy.sls
@@ -0,0 +1,25 @@
+{%- from "linux/map.jinja" import network with context %}
+{%- if network.enabled %}
+
+{%- if grains.os_family == 'Debian' %}
+
+{%- if network.proxy.host == 'none' %}
+
+/etc/profile.d/proxy.sh:
+  file.absent
+
+/etc/apt/apt.conf.d/95proxies:
+  file.absent
+
+{%- else %}
+
+/etc/apt/apt.conf.d/95proxies:
+  file.managed:
+  - template: jinja
+  - source: salt://linux/files/95proxies
+
+{%- endif %}
+
+{%- endif %}
+
+{%- endif %}
diff --git a/linux/storage/init.sls b/linux/storage/init.sls
new file mode 100644
index 0000000..f4f90e9
--- /dev/null
+++ b/linux/storage/init.sls
@@ -0,0 +1,13 @@
+{%- from "linux/map.jinja" import storage with context %}
+{%- if storage.mount|length > 0 or storage.swap|length > 0 or storage.multipath %}
+include:
+{%- if storage.mount|length > 0 %}
+- linux.storage.mount
+{%- endif %}
+{%- if storage.swap|length > 0 %}
+- linux.storage.swap
+{%- endif %}
+{%- if storage.multipath %}
+- linux.storage.multipath
+{%- endif %}
+{%- endif %}
diff --git a/linux/storage/mount.sls b/linux/storage/mount.sls
new file mode 100644
index 0000000..038c4ad
--- /dev/null
+++ b/linux/storage/mount.sls
@@ -0,0 +1,26 @@
+{%- from "linux/map.jinja" import storage with context %}
+{%- if storage.enabled %}
+
+{%- for name, mount in storage.mount.iteritems() %}
+
+{%- if mount.enabled %}
+
+mkfs_{{ mount.device}}:
+  cmd.run:
+  - name: "mkfs.{{ mount.file_system }} -L {{ name }} {{ mount.device }}"
+  - onlyif: "test `blkid {{ mount.device }} >/dev/null;echo $?` -eq 2"
+  - require_in:
+    - mount: {{ mount.path }}
+
+{{ mount.path }}:
+  mount.mounted:
+  - device: {{ mount.device }}
+  - fstype: {{ mount.file_system }}
+  - mkmnt: True
+  - opts: {{ mount.get('opts', 'defaults,noatime') }}
+
+{%- endif %}
+
+{%- endfor %}
+
+{%- endif %}
diff --git a/linux/storage/multipath.sls b/linux/storage/multipath.sls
new file mode 100644
index 0000000..ae9151a
--- /dev/null
+++ b/linux/storage/multipath.sls
@@ -0,0 +1,48 @@
+{%- from "linux/map.jinja" import storage with context %}
+{%- if storage.enabled %}
+
+{%- if grains.os_family == 'Debian' %}
+
+linux_multipath_pkgs:
+  pkg.installed:
+  - names: {{ storage.multipath_pkgs }}
+
+{%- if storage.multipath.backend not in ['fujitsu'] %}
+
+linux_multipath_boot_pkg:
+  pkg.installed:
+  - name: multipath-tools-boot
+
+{%- endif %}
+
+{%- if storage.multipath.backend == 'HDS' %}
+
+/etc/multipath.conf:
+  file.managed:
+  - source: salt://linux/files/multipath.conf.hds
+  - template: jinja
+  - require:
+    - pkg: linux_multipath_pkgs
+
+{%- else %}
+
+/etc/multipath.conf:
+  file.managed:
+  - source: salt://linux/files/multipath.conf
+  - template: jinja
+  - require:
+    - pkg: linux_multipath_pkgs
+
+{%- endif %}
+
+multipath_service:
+  service.running:
+  - enable: True
+  - name: multipath-tools
+  - watch:
+    - file: /etc/multipath.conf
+  - sig: multipathd
+
+{%- endif %}
+
+{%- endif %}
diff --git a/linux/storage/swap.sls b/linux/storage/swap.sls
new file mode 100644
index 0000000..81694e9
--- /dev/null
+++ b/linux/storage/swap.sls
@@ -0,0 +1,40 @@
+{%- from "linux/map.jinja" import storage with context %}
+{%- if storage.enabled %}
+
+{%- for swap_name, swap in storage.swap.iteritems() %}
+
+{%- if swap.enabled %}
+
+{%- if swap.engine == 'file' %}
+
+linux_create_swap_file_{{ swap.device }}:
+  cmd.run:
+  - name: 'dd if=/dev/zero of={{ swap.device }} bs=1048576 count={{ swap.size }} && chmod 0600 {{ swap.device }}'
+  - creates: {{ swap.device }}
+
+linux_set_swap_file_{{ swap.device }}:
+  cmd.wait:
+  - name: 'mkswap {{ swap.device }}'
+  - watch:
+    - cmd: linux_create_swap_file_{{ swap.device }}
+
+linux_set_swap_file_status_{{ swap.device }}:
+  cmd.run:
+  - name: 'swapon {{ swap.device }}'
+  - unless: grep {{ swap.device }} /proc/swaps
+  - require:
+    - cmd: linux_set_swap_file_{{ swap.device }}
+
+{{ swap.device }}:
+  mount.swap:
+  - persist: True
+  - require:
+    - cmd: linux_set_swap_file_{{ swap.device }}
+
+{%- endif %}
+
+{%- endif %}
+
+{%- endfor %}
+
+{%- endif %}
diff --git a/linux/system/apparmor.sls b/linux/system/apparmor.sls
new file mode 100644
index 0000000..1aa5109
--- /dev/null
+++ b/linux/system/apparmor.sls
@@ -0,0 +1,28 @@
+{%- from "linux/map.jinja" import system with context %}
+
+include:
+- linux.system.package
+
+{%- if system.apparmor.enabled %}
+
+apparmor_service:
+  service.running:
+  - name: apparmor
+  - enable: true
+  - require:
+    - pkg: linux_packages
+
+{%- else %}
+
+apparmor_service_disable:
+  service.dead:
+    name: apparmor
+    enable: false
+
+apparmor_teardown:
+  cmd.wait:
+  - name: /etc/init.d/apparmor teardown
+  - watch:
+    - service: apparmor_service_disable
+
+{%- endif %}
diff --git a/linux/system/certificate.sls b/linux/system/certificate.sls
new file mode 100644
index 0000000..a342cbe
--- /dev/null
+++ b/linux/system/certificate.sls
@@ -0,0 +1,22 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+
+{%- if system.ca_certificates is defined %}
+
+{%- for certificate in system.ca_certificates %}
+
+{{ system.ca_certs_dir }}/{{ certificate }}.crt:
+  file.managed:
+  - source: salt://pki/{{ certificate }}/{{ certificate }}-chain.cert.pem
+  - watch_in:
+    - cmd: update_certificates
+
+{%- endfor %}
+
+update_certificates:
+  cmd.wait:
+  - name: /usr/sbin/update-ca-certificates
+
+{%- endif %}
+
+{%- endif %}
diff --git a/linux/system/group.sls b/linux/system/group.sls
new file mode 100644
index 0000000..4963829
--- /dev/null
+++ b/linux/system/group.sls
@@ -0,0 +1,28 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+
+{%- for group_name, group in system.group.iteritems() %}
+
+{%- if group.enabled %}
+
+system_group_{{ group_name }}:
+  group.present:
+  - name: {{ group.name }}
+  {%- if group.system is defined and group.system %}
+  - system: True
+  {%- endif %}
+  {%- if group.gid is defined and group.gid %}
+  - gid: {{ group.gid }}
+  {%- endif %}
+
+{%- else %}
+
+system_group_{{ group_name }}:
+  group.absent:
+  - name: {{ group.name }}
+
+{%- endif %}
+
+{%- endfor %}
+
+{%- endif %}
diff --git a/linux/system/init.sls b/linux/system/init.sls
new file mode 100644
index 0000000..b8b3a48
--- /dev/null
+++ b/linux/system/init.sls
@@ -0,0 +1,35 @@
+{%- from "linux/map.jinja" import system with context %}
+include:
+{%- if system.repo|length > 0 %}
+- linux.system.repo
+{%- endif %}
+{%- if system.pkgs|length > 0 %}
+- linux.system.package
+{%- endif %}
+{%- if system.timezone is defined %}
+- linux.system.timezone
+{%- endif %}
+{%- if system.kernel is defined %}
+- linux.system.kernel
+{%- endif %}
+{%- if system.locale is defined %}
+- linux.system.locale
+{%- endif %}
+{%- if system.user|length > 0 %}
+- linux.system.user
+{%- endif %}
+{%- if system.group|length > 0 %}
+- linux.system.group
+{%- endif %}
+{%- if system.job|length > 0 %}
+- linux.system.job
+{%- endif %}
+{%- if grains.os_family == 'RedHat' %}
+- linux.system.selinux
+{%- endif %}
+{%- if system.ca_certificates is defined %}
+- linux.system.certificate
+{%- endif %}
+{%- if system.apparmor is defined %}
+- linux.system.apparmor
+{%- endif %}
diff --git a/linux/system/job.sls b/linux/system/job.sls
new file mode 100644
index 0000000..d589023
--- /dev/null
+++ b/linux/system/job.sls
@@ -0,0 +1,33 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+
+{%- for name, job in system.job.iteritems() %}
+
+linux_job_{{ job.command }}:
+  {%- if job.enabled %}
+  cron.present:
+    - name: {{ job.command }}
+    - user: {{ job.user }}
+    {%- if job.minute is defined %}
+    - minute: '{{ job.minute }}'
+    {%- endif %}
+    {%- if job.hour is defined %}
+    - hour: '{{ job.hour }}'
+    {%- endif %}
+    {%- if job.daymonth is defined %}
+    - daymonth: '{{ job.daymonth }}'
+    {%- endif %}
+    {%- if job.month is defined %}
+    - month: '{{ job.month }}'
+    {%- endif %}
+    {%- if job.dayweek is defined %}
+    - dayweek: '{{ job.dayweek }}'
+    {%- endif %}
+  {%- else %}
+  job.absent:
+    - name: {{ job.command }}
+  {%- endif %}
+
+{%- endfor %}
+
+{%- endif %}
\ No newline at end of file
diff --git a/linux/system/kernel.sls b/linux/system/kernel.sls
new file mode 100644
index 0000000..4732e2d
--- /dev/null
+++ b/linux/system/kernel.sls
@@ -0,0 +1,73 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+
+{%- if system.kernel is defined %}
+
+Basic kernel:
+
+  linux:
+    system:
+      kernel:
+        hold: true
+        versions:
+          generic:
+            headers: true
+
+
+  linux:
+    system:
+      kernel:
+        source:
+          engine: pkg
+          repo: from_repo
+        version: 1.13.42
+        hold: true
+        headers: true
+        generic: true
+
+linux-headers-3.13.0-34
+linux-image-3.13.0-34-generic
+linux-headers-3.13.0-34-generic
+
+{%- if system.kernel.get('source', {'engine': 'pkg'}).engine == 'pkg' %}
+
+{%- if system.kernel.version is defined %}
+
+linux_kernel_package:
+  pkg.installed:
+  - name: linux-image-{{ system.kernel.version }}
+  - refresh: true
+
+{%- else %}
+
+linux_kernel_package:
+  pkg.latest:
+  - name: linux-image-generic
+  - refresh: true
+
+{%- endif %}
+
+{%- if system.kernel.headers is defined %}
+{%- if system.kernel.version is defined %}
+
+linux_kernel_package:
+  pkg.installed:
+  - name: linux-image-{{ system.kernel.version }}
+  - version: 
+  - refresh: true
+
+{%- else %}
+
+linux_kernel_package:
+  pkg.latest:
+  - name: linux-image-generic
+  - refresh: true
+
+{%- endif %}
+{%- endif %}
+
+{%- endif %}
+
+{%- endif %}
+
+{%- endif %}
\ No newline at end of file
diff --git a/linux/system/locale.sls b/linux/system/locale.sls
new file mode 100644
index 0000000..1b006b5
--- /dev/null
+++ b/linux/system/locale.sls
@@ -0,0 +1,4 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+
+{%- endif %}
\ No newline at end of file
diff --git a/linux/system/package.sls b/linux/system/package.sls
new file mode 100644
index 0000000..cd9d2cc
--- /dev/null
+++ b/linux/system/package.sls
@@ -0,0 +1,29 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+
+linux_packages:
+  pkg.installed:
+  - names: {{ system.pkgs }}
+
+{%- for name, package in system.package.iteritems() %}
+
+linux_extra_package_{{ name }}:
+  {%- if package.version == 'latest' %}
+  pkg.latest:
+  {%- else %}
+  pkg.installed:
+  - version: {{ package.version }}
+  {%- endif %}
+  - name: {{ name }}
+  {%- if package.repo is defined %}
+  - fromrepo: {{ package.repo }}
+  {%- endif %}
+  {%- if package.hold is defined %}
+  - hold: {{ package.hold }}
+  {%- endif %}
+  {%- if package.verify is defined %}
+  - skip_verify: {% if package.verify %}false{% else %}true{% endif %}
+  {%- endif %}
+{%- endfor %}
+
+{%- endif %}
\ No newline at end of file
diff --git a/linux/system/repo.sls b/linux/system/repo.sls
new file mode 100644
index 0000000..803ca56
--- /dev/null
+++ b/linux/system/repo.sls
@@ -0,0 +1,98 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+
+{% set default_repos = {} %}
+
+{%- for name, repo in system.repo.iteritems() %}
+
+{%- if grains.os_family == 'Debian' %}
+
+{%- if repo.pin is defined %}
+
+linux_repo_{{ name }}_pin:
+  file.managed:
+    - name: /etc/apt/preferences.d/{{ name }}
+    - source: salt://linux/files/preferences_repo
+    - template: jinja
+    - defaults:
+        repo_name: {{ name }}
+
+{%- else %}
+
+linux_repo_{{ name }}_pin:
+  file.absent:
+    - name: /etc/apt/preferences.d/{{ name }}
+
+{%- endif %}
+
+{%- if repo.get('default', False) %}
+
+{%- do default_repos.update({name: repo}) %}
+
+{%- if repo.key_url %}
+
+linux_repo_{{ name }}_key:
+  cmd.wait:
+    - name: "curl -s {{ repo.key_url }} | apt-key add -"
+    - watch:
+      - file: default_repo_list
+
+{%- endif %}
+
+{%- else %}
+
+linux_repo_{{ name }}:
+  pkgrepo.managed:
+  - human_name: {{ name }}
+  - name: {{ repo.source }}
+  {%- if repo.architectures is defined %}
+  - architectures: {{ repo.architectures }}
+  {%- endif %}
+  - file: /etc/apt/sources.list.d/{{ name }}.list
+  {%- if repo.key_id is defined %}
+  - keyid: {{ repo.key_id }}
+  {%- endif %}
+  {%- if repo.key_server is defined %}
+  - keyserver: {{ repo.key_server }}
+  {%- endif %}
+  {%- if repo.key_url is defined %}
+  - key_url: {{ repo.key_url }}
+  {%- endif %}
+
+{%- endif %}
+
+{%- endif %}
+
+{%- if grains.os_family == "RedHat" %}
+
+{%- if not repo.get('default', False) %}
+
+linux_repo_{{ name }}:
+  pkgrepo.managed:
+  - name: {{ name }}
+  - humanname: {{ name }}
+  - baseurl: {{ repo.source }}
+  - gpgcheck: {% if repo.get('gpgcheck', False) %}1{% else %}0{% endif %}
+
+{%- endif %}
+
+{%- endif %}
+
+{%- endfor %}
+
+{%- if default_repos|length > 0 and grains.os_family == 'Debian' %}
+
+default_repo_list:
+  file.managed:
+    - name: /etc/apt/sources.list
+    - source: salt://linux/files/sources.list
+    - template: jinja
+    - user: root
+    - group: root
+    - mode: 0644
+    - defaults:
+        default_repos: {{ default_repos }}
+
+{%- endif %}
+
+{%- endif %}
diff --git a/linux/system/selinux.sls b/linux/system/selinux.sls
new file mode 100644
index 0000000..a91ed2e
--- /dev/null
+++ b/linux/system/selinux.sls
@@ -0,0 +1,30 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+
+include:
+- linux.system.package
+
+{%- if grains.os_family == 'RedHat' %}
+
+{%- if system.selinux == 'disabled' %}
+
+selinux_config:
+  cmd.run:
+  - names:
+    - "sed -i 's/enforcing/disabled/g' /etc/selinux/config; setenforce 0"
+    - "sed -i 's/permissive/disabled/g' /etc/selinux/config; setenforce 0"
+  - unless: cat '/etc/selinux/config' | grep 'SELINUX=disabled'
+
+{%- else %}
+
+selinux_config:
+  selinux.mode:
+  - name: {{ system.get('selinux', 'permissive') }}
+  - require:
+    - pkg: linux_packages
+
+{%- endif %}
+
+{%- endif %}
+
+{%- endif %}
\ No newline at end of file
diff --git a/linux/system/timezone.sls b/linux/system/timezone.sls
new file mode 100644
index 0000000..6b8e778
--- /dev/null
+++ b/linux/system/timezone.sls
@@ -0,0 +1,12 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+
+{%- if system.timezone is defined %}
+
+{{ system.timezone }}:
+  timezone.system:
+  - utc: {{ system.utc }}
+
+{%- endif %}
+
+{%- endif %}
\ No newline at end of file
diff --git a/linux/system/user.sls b/linux/system/user.sls
new file mode 100644
index 0000000..9b5fd9e
--- /dev/null
+++ b/linux/system/user.sls
@@ -0,0 +1,71 @@
+{%- from "linux/map.jinja" import system with context %}
+{%- if system.enabled %}
+
+{%- for name, user in system.user.iteritems() %}
+
+{%- if user.enabled %}
+
+system_user_{{ name }}:
+  user.present:
+  - name: {{ name }}
+  - home: {{ user.home }}
+  {%- if user.password is defined %}
+  - password: {{ user.password }}
+  - enforce_password: true
+  - gid_from_name: true
+  {%- endif %}
+  {%- if user.groups is defined %}
+  - groups: {{ user.groups }}
+  {%- endif %}
+  {%- if user.system is defined and user.system %}
+  - system: True
+  {%- else %}
+  - shell: {{ user.get('shell', '/bin/bash') }}
+  {%- endif %}
+  {%- if user.uid is defined and user.uid %}
+  - uid: {{ user.uid }}
+  {%- endif %}
+
+system_user_home_{{ user.home }}:
+  file.directory:
+  - name: {{ user.home }}
+  - user: {{ name }}
+  - mode: 700
+  - makedirs: true
+  - require:
+    - user: system_user_{{ name }}
+
+{%- if user.get('sudo', False) %}
+
+/etc/sudoers.d/90-salt-user-{{ name }}:
+  file.managed:
+  - source: salt://linux/files/sudoer
+  - template: jinja
+  - user: root
+  - group: root
+  - mode: 440
+  - defaults:
+    user_name: {{ name }}
+  - require:
+    - user: system_user_{{ name }}
+
+{%- endif %}
+
+{%- else %}
+
+system_user_{{ name }}:
+  user.absent:
+  - name: {{ name }}
+
+system_user_home_{{ user.home }}:
+  file.absent:
+  - name: {{ user.home }}
+
+/etc/sudoers.d/90-salt-user-{{ name }}:
+  file.absent
+
+{%- endif %}
+
+{%- endfor %}
+
+{%- endif %}
diff --git a/metadata/service/system/init.yml b/metadata/service/system/init.yml
new file mode 100644
index 0000000..d239c14
--- /dev/null
+++ b/metadata/service/system/init.yml
@@ -0,0 +1,19 @@
+applications:
+- linux
+parameters:
+  linux:
+    system:
+      enabled: true
+      user:
+        root:
+          enabled: true
+          name: root
+          home: /root
+      timezone: Europe/Prague
+      cluster: default
+    network:
+      enabled: true
+      hostname: ${linux:system:name}
+      fqdn: ${linux:system:name}.${linux:system:domain}
+    storage:
+      enabled: true