Initial commit
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
new file mode 100644
index 0000000..5972c61
--- /dev/null
+++ b/CHANGELOG.rst
@@ -0,0 +1,6 @@
+glusterfs
+=========
+
+0.1 (2015-07-30)
+
+- initial release
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0c7e4d8
--- /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..69dc159
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,123 @@
+=========
+GlusterFS
+=========
+
+Install and configure GlusterFS server and client.
+
+Available states
+================
+
+.. contents::
+    :local:
+
+``glusterfs.server``
+--------------------
+
+Setup GlusterFS server
+
+``glusterfs.client``
+--------------------
+
+Setup GlusterFS client
+
+Available metadata
+==================
+
+.. contents::
+    :local:
+
+``metadata.glusterfs.server``
+-----------------------------
+
+Setup basic server
+
+
+``metadata.glusterfs.client``
+-----------------------------
+
+Setup client only
+
+Configuration parameters
+========================
+
+
+Example reclass
+===============
+
+Example for distributed glance images storage where every control node is
+gluster peer.
+
+.. code-block:: yaml
+
+   classes:
+   - service.glusterfs.server
+   - service.glusterfs.client
+
+   _param:
+     cluster_node01_address: 192.168.1.21
+     cluster_node02_address: 192.168.1.22
+     cluster_node03_address: 192.168.1.23
+   parameters:
+     glusterfs:
+       server:
+         peers:
+         - ${_param:cluster_node01_address}
+         - ${_param:cluster_node02_address}
+         - ${_param:cluster_node03_address}
+         volumes:
+            glance:
+              storage: /srv/glusterfs/glance
+              replica: 3
+              bricks:
+              - ${_param:cluster_node01_address}:/srv/glusterfs/glance
+              - ${_param:cluster_node02_address}:/srv/glusterfs/glance
+              - ${_param:cluster_node03_address}:/srv/glusterfs/glance
+       client:
+         volumes:
+           glance:
+             path: /var/lib/glance/images
+             server: ${_param:cluster_node01_address}
+             user: glance
+             group: glance
+
+Example pillar
+==============
+
+Server
+------
+
+.. code-block:: yaml
+
+   glusterfs:
+     server:
+       peers:
+       - 192.168.1.21
+       - 192.168.1.22
+       - 192.168.1.23
+       volumes:
+          glance:
+            storage: /srv/glusterfs/glance
+            replica: 3
+            bricks:
+            - 172.168.1.21:/srv/glusterfs/glance
+            - 172.168.1.21:/srv/glusterfs/glance
+            - 172.168.1.21:/srv/glusterfs/glance
+
+Client
+------
+
+.. code-block:: yaml
+
+   glusterfs:
+     client:
+       volumes:
+         glance:
+           path: /var/lib/glance/images
+           server: 192.168.1.21
+           user: glance
+           group: glance
+
+Read more
+=========
+
+* https://www.gluster.org/
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..49d5957
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.1
diff --git a/glusterfs/client.sls b/glusterfs/client.sls
new file mode 100644
index 0000000..b4a20aa
--- /dev/null
+++ b/glusterfs/client.sls
@@ -0,0 +1,39 @@
+{% from "glusterfs/map.jinja" import client with context %}
+
+{%- if client.enabled %}
+
+glusterfs_client_packages:
+  pkg.installed:
+    - names: {{ client.pkgs }}
+
+{%- if client.volumes is defined %}
+{%- for name, volume in client.volumes.iteritems() %}
+
+glusterfs_mount_{{ name }}:
+  mount.mounted:
+    - name: {{ volume.path }}
+    - device: {{ volume.server }}:/{{ name }}
+    - fstype: glusterfs
+    - mkmnt: true
+    - opts: {{ volume.get('opts', 'defaults') }}
+    - require:
+      - pkg: glusterfs_client_packages
+
+{# Fix privileges on mount #}
+{%- if volume.user is defined or volume.group is defined %}
+
+glusterfs_dir_{{ name }}:
+  file.directory:
+    - name: {{ volume.path }}
+    - user: {{ volume.get('user', 'root') }}
+    - group: {{ volume.get('group', 'root') }}
+    - mode: {{ volume.get('mode', '755') }}
+    - require:
+      - mount: glusterfs_mount_{{ name }}
+
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- endif %}
diff --git a/glusterfs/init.sls b/glusterfs/init.sls
new file mode 100644
index 0000000..b1630bf
--- /dev/null
+++ b/glusterfs/init.sls
@@ -0,0 +1,7 @@
+include:
+{% if pillar.glusterfs.server is defined %}
+- glusterfs.server
+{% endif %}
+{% if pillar.glusterfs.client is defined %}
+- glusterfs.client
+{% endif %}
diff --git a/glusterfs/map.jinja b/glusterfs/map.jinja
new file mode 100644
index 0000000..d6dfe16
--- /dev/null
+++ b/glusterfs/map.jinja
@@ -0,0 +1,19 @@
+{% set server = salt['grains.filter_by']({
+    'Debian': {
+        'pkgs': ['glusterfs-server'],
+        'service': 'glusterfs-server',
+    },
+    'RedHat': {
+        'pkgs': ['glusterfs-server'],
+        'service': 'glusterd',
+    },
+}, merge=salt['pillar.get']('glusterfs:server')) %}
+
+{% set client = salt['grains.filter_by']({
+    'Debian': {
+        'pkgs': ['glusterfs-client'],
+    },
+    'RedHat': {
+        'pkgs': ['glusterfs-client'],
+    },
+}, merge=salt['pillar.get']('glusterfs:client')) %}
diff --git a/glusterfs/server.sls b/glusterfs/server.sls
new file mode 100644
index 0000000..bc9c7ee
--- /dev/null
+++ b/glusterfs/server.sls
@@ -0,0 +1,53 @@
+{% from "glusterfs/map.jinja" import server with context %}
+
+{%- if server.enabled %}
+
+glusterfs_packages:
+  pkg.installed:
+    - names: {{ server.pkgs }}
+
+glusterfs_service:
+  service.running:
+    - name: {{ server.service }}
+    - require:
+      - pkg: glusterfs_packages
+
+{%- if server.peers is defined %}
+
+glusterfs_peers:
+    glusterfs.peered:
+      - names: {{ server.peers }}
+      - require:
+        - service: glusterfs_service
+
+{%- endif %}
+
+{%- if server.volumes is defined %}
+{%- for name, volume in server.volumes.iteritems() %}
+
+{{ volume.storage }}:
+  file.directory:
+    - makedirs: true
+
+glusterfs_vol_{{ name }}:
+  glusterfs.created:
+    - name: {{ name }}
+    {%- if volume.replica is defined %}
+    - replica: {{ volume.replica }}
+    {%- endif %}
+    {%- if volume.stripe is defined %}
+    - stripe: {{ volume.stripe }}
+    {%- endif %}
+    - bricks: {{ volume.bricks }}
+    - start: true
+    {# Parameter force doesn't exist in Salt 2015.5.2 and without it creation
+    will fail when brick is on root disk #}
+    - force: true
+    - require:
+      - glusterfs: glusterfs_peers
+      - file: {{ volume.storage }}
+
+{%- endfor %}
+{%- endif %}
+
+{%- endif %}
diff --git a/metadata/service/client.yml b/metadata/service/client.yml
new file mode 100644
index 0000000..86b98fc
--- /dev/null
+++ b/metadata/service/client.yml
@@ -0,0 +1,6 @@
+applications:
+  - glusterfs
+parameters:
+  glusterfs:
+    client:
+      enabled: true
diff --git a/metadata/service/server.yml b/metadata/service/server.yml
new file mode 100644
index 0000000..136148d
--- /dev/null
+++ b/metadata/service/server.yml
@@ -0,0 +1,6 @@
+applications:
+  - glusterfs
+parameters:
+  glusterfs:
+    server:
+      enabled: true