Gerrit client and project enforcement
diff --git a/README.rst b/README.rst
index a7f9cc3..0cca655 100644
--- a/README.rst
+++ b/README.rst
@@ -8,7 +8,7 @@
 Sample pillars
 ==============
 
-Sipmple gerrit service
+Simple gerrit service
 
 .. code-block:: yaml
 
@@ -20,6 +20,77 @@
           address: https://gerrit-ci.gerritforge.com/job/Gerrit-stable-2.13/20/artifact/buck-out/gen/gerrit.war
           hash: 2e17064b8742c4622815593ec496c571
 
+Full service setup
+
+.. code-block:: yaml
+
+    gerrit:
+      server:
+        canonical_web_url: http://10.10.10.148:8082/
+        email_private_key: ""
+        token_private_key: ""
+        initial_user:
+          full_name: John Doe
+          email: 'mail@jdoe.com'
+          username: jdoe
+        plugin:
+          download-commands:
+            engine: gerrit
+  #        replication:
+  #          engine: gerrit
+          reviewnotes:
+            engine: gerrit
+          singleusergroup:
+            engine: gerrit
+        ssh_rsa_key: |
+          -----BEGIN RSA PRIVATE KEY-----
+          MIIEowIBAAKCAQEAs0Y8mxS3dfs5zG8Du5vdBkfOCOng1IEUmFZIirJ8oBgJOd54
+          QgmkDFB7oP9eTCgz9k/rix1uJWhhVCMBzrWzH5IODO+tyy/tK66pv2BWtVfTDhBA
+          nShOLDNbSIBaV8E/NcrbnQN+b0alp4N7rQnavkOYl+JQncKjz1csmCodirscB9Oj
+          rdo6NG9olv9IQd/tDQxEeDyQkoW50aCEWcq7o+QaTzgnlrL+XZEzhzjdcvA9m8go
+          ...
+          jvMXms60iD/A5OpG33LWHNNzQBP486SxG75LB+Xs5sp5j2/b7VF5LJLhpGiJv9Mk
+          ydbuy8iuuvali2uF133kAlLqnrWfVTYQQI1OfW5glOv1L6kv94dU
+          -----END RSA PRIVATE KEY-----
+        ssh_rsa_key_pub: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCzRjybFLd1+znMbwO7m90GR84I6eDUgRSYVkiKsnygGAk53nhCCaQMUHug/15MKDP2T+uLHW4laGFUIwHOtbMfkg4M763LL+0rrqm/YFa1V9MOEECdKE4sM1tIgFpXwT81ytudA35vRqWng3utCdq+Q5iX4lCdwqPPVyyYKh2KuxwH06Ot2jo0b2iW/0hB3+0NDER4PJCShbnRoIRZyruj5BpPOCeWsv5dkTOHON1y8D2byCgNGdCBIRx7x9Qb4dKK2F01r0/bfBGxELJzBdQ8XO14bQ7VOd3gTxrccTM4tVS7/uc/vtjiq7MKjnHGf/svbw9bTHAXbXcWXtOlRe51
+        email: mail@domain.com
+        auth:
+          engine: HTTP
+        source:
+          engine: http
+          address: https://gerrit-releases.storage.googleapis.com/gerrit-2.12.4.war
+          hash: sha256=45786a920a929c6258de6461bcf03ddec8925577bd485905f102ceb6e5e1e47c
+        database:
+          engine: postgresql
+          host: localhost
+          port: 5432
+          name: gerrit
+          user: gerrit
+          password: ${_param:postgresql_gerrit_password}
+
+Gerrit client enforcing projects
+
+.. code-block:: yaml
+
+    gerrit:
+      client:
+        enabled: True
+        server: 
+          host: 10.10.10.148
+          user: newt
+          key: |
+            -----BEGIN RSA PRIVATE KEY-----
+            MIIEowIBAAKCAQEAs0Y8mxS3dfs5zG8Du5vdBkfOCOng1IEUmFZIirJ8oBgJOd54
+            QgmkDFB7oP9eTCgz9k/rix1uJWhhVCMBzrWzH5IODO+tyy/tK66pv2BWtVfTDhBA
+            ...
+            l1UrxQKBgEklBTuEiDRibKGXQBwlAYvK2He09hWpqtpt9/DVel6s4A1bbTWDHyoP
+            jvMXms60iD/A5OpG33LWHNNzQBP486SxG75LB+Xs5sp5j2/b7VF5LJLhpGiJv9Mk
+            ydbuy8iuuvali2uF133kAlLqnrWfVTYQQI1OfW5glOv1L6kv94dU
+            -----END RSA PRIVATE KEY-----
+        project:
+          test_salt_project:
+            enabled: true
+
 Read more
 =========
 
diff --git a/_modules/gerrit.py b/_modules/gerrit.py
new file mode 100644
index 0000000..c4048cf
--- /dev/null
+++ b/_modules/gerrit.py
@@ -0,0 +1,155 @@
+# -*- coding: utf-8 -*-
+'''
+Module for handling gerrit calls.
+
+:optdepends:    - gerritlib Python adapter
+:configuration: This module is not usable until the following are specified
+    either in a pillar or in the minion's config file::
+
+        gerrit.host: localhost
+        gerrit.user: admin
+        gerrit.key: |
+            -----BEGIN RSA PRIVATE KEY-----
+            MIIEowIBAAKCAQEAs0Y8mxS3dfs5zG8Du5vdBkfOCOng1IEUmFZIirJ8oBgJOd54
+            ...
+            jvMXms60iD/A5OpG33LWHNNzQBP486SxG75LB+Xs5sp5j2/b7VF5LJLhpGiJv9Mk
+            ydbuy8iuuvali2uF133kAlLqnrWfVTYQQI1OfW5glOv1L6kv94dU
+            -----END RSA PRIVATE KEY-----
+
+'''
+
+from __future__ import absolute_import
+
+import logging
+import os
+
+LOG = logging.getLogger(__name__)
+
+# Import third party libs
+HAS_GERRIT = False
+try:
+    from gerritlib import gerrit
+    HAS_GERRIT = True
+except ImportError:
+    pass
+
+
+def __virtual__():
+    '''
+    Only load this module if gerrit
+    is installed on this minion.
+    '''
+    if HAS_GERRIT:
+        return 'gerrit'
+    return False
+
+__opts__ = {}
+
+
+def auth(**connection_args):
+    '''
+    Set up gerrit credentials
+
+    Only intended to be used within gerrit-enabled modules
+    '''
+   
+    prefix = "gerrit"
+
+    # look in connection_args first, then default to config file
+    def get(key, default=None):
+        return connection_args.get('connection_' + key,
+            __salt__['config.get'](prefix, {})).get(key, default)
+
+    host = get('host', 'localhost')
+    user = get('user', 'admin')
+    keyfile = get('keyfile', '/var/cache/salt/minion/gerrit_rsa')   
+
+    gerrit_client = gerrit.Gerrit(host, user, keyfile=keyfile)
+    return gerrit_client
+
+
+def project_create(name, **kwargs):
+    '''
+    Create a gerrit project
+
+    :param name: new project name
+
+    CLI Examples:
+
+    .. code-block:: bash
+
+        salt '*' gerrit.project_create namespace/nova description='nova project'
+    
+    '''
+    ret = {}
+    gerrit_client = auth(**kwargs)
+
+    project = project_get(name, **kwargs)
+
+    if project and not "Error" in project:
+        LOG.debug("Project {0} exists".format(name))
+        return project
+
+    new = gerrit_client.createProject(name)
+    return project_get(name, **kwargs)
+
+def project_get(name, **kwargs):
+    '''
+    Return a specific project
+
+    CLI Examples:
+
+    .. code-block:: bash
+
+        salt '*' gerrit.project_get projectname
+    '''
+    gerrit_client = auth(**kwargs)
+    ret = {}
+
+    projects = gerrit_client.listProjects()
+    if not name in projects:
+        return {'Error': 'Error in retrieving project'}
+    ret[name] = {'name': name}
+    return ret
+
+
+def project_list(**connection_args):
+    '''
+    Return a list of available projects
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' gerrit.project_list
+    '''
+    gerrit_client = auth(**connection_args)
+    ret = {}
+
+    projects = gerrit_client.listProjects()
+
+    for project in projects:
+        ret[project] = {
+            'name': project
+        }
+    return ret
+
+
+def query(change, **kwargs):
+    '''
+    Query gerrit
+
+    :param change: Query content
+
+    CLI Examples:
+
+    .. code-block:: bash
+
+        salt '*' gerrit.query 'status:open project:tools/gerrit limit:2'
+    
+    '''
+    ret = {}
+    gerrit_client = auth(**kwargs)
+    msg = gerrit_client.query(change)
+    ret['query'] = msg
+    return ret
diff --git a/_states/gerrit.py b/_states/gerrit.py
new file mode 100644
index 0000000..8bbdb77
--- /dev/null
+++ b/_states/gerrit.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+'''
+Management of gerrit projects
+==============================
+
+:depends:   - gerritlib Python module
+:configuration: See :py:mod:`salt.modules.gerrit` for setup instructions.
+
+.. code-block:: yaml
+
+    gerrit project:
+      gerrit.project_present:
+      - name: gerrit project
+
+'''
+
+
+def __virtual__():
+    '''
+    Only load if the gerrit module is in __salt__
+    '''
+    return 'gerrit' if 'gerrit.auth' in __salt__ else False
+
+
+def project_present(name, description=None, **kwargs):
+    '''
+    Ensures that the gerrit project exists
+    
+    :param name: new project name
+    :param description: short project description
+    '''
+    ret = {'name': name,
+           'changes': {},
+           'result': True,
+           'comment': 'Project "{0}" already exists'.format(name)}
+
+    # Check if project is already present
+    project = __salt__['gerrit.project_get'](name=name, **kwargs)
+
+    if 'Error' not in project:
+        #update project
+        pass
+    else:
+        # Create project
+        __salt__['gerrit.project_create'](name, **kwargs)
+        ret['comment'] = 'Project "{0}" has been added'.format(name)
+        ret['changes']['Project'] = 'Created'
+    return ret
diff --git a/gerrit/_modules/gerrit.py b/gerrit/_modules/gerrit.py
deleted file mode 100644
index 66cf0d3..0000000
--- a/gerrit/_modules/gerrit.py
+++ /dev/null
@@ -1,228 +0,0 @@
-# -*- coding: utf-8 -*-
-'''
-Module for handling gerrit calls.
-
-:optdepends:    - gerritlib Python adapter
-:configuration: This module is not usable until the following are specified
-    either in a pillar or in the minion's config file::
-
-        gerrit.host: localhost
-        gerrit.user: admin
-        gerrit.keyfile: /tmp/key.pub
-
-'''
-
-from __future__ import absolute_import
-
-import logging
-import os
-
-LOG = logging.getLogger(__name__)
-
-# Import third party libs
-HAS_GERRIT = False
-try:
-    from gerritlib import gerrit
-    HAS_GERRIT = True
-except ImportError:
-    pass
-
-
-def __virtual__():
-    '''
-    Only load this module if gerrit
-    is installed on this minion.
-    '''
-    if HAS_GERRIT:
-        return 'gerrit'
-    return False
-
-__opts__ = {}
-
-
-def auth(**connection_args):
-    '''
-    Set up gerrit credentials
-
-    Only intended to be used within gerrit-enabled modules
-    '''
-   
-    prefix = "gerrit."
-
-    # look in connection_args first, then default to config file
-    def get(key, default=None):
-        return connection_args.get('connection_' + key,
-            __salt__['config.get'](prefix + key, default))
-
-    host = get('host', 'localhost')
-    user = get('user', 'localhost')   
-    keyfile = get('keyfile', '/tmp/.ssh/id_rsa.pub')   
-
-    g = gerrit.Gerrit(host, user, keyfile=keyfile)
-
-
-def project_create(name, **kwargs):
-    '''
-    Create a gerrit project
-
-    :param name: new project name
-    :param path: custom repository name for new project. By default generated based on name
-    :param namespace_id: namespace for the new project (defaults to user)
-    :param description: short project description
-    :param issues_enabled:
-    :param merge_requests_enabled:
-    :param wiki_enabled:
-    :param snippets_enabled:
-    :param public: if true same as setting visibility_level = 20
-    :param visibility_level:
-    :param import_url: https://gerrit.tcpcloud.eu/django/django-kedb.gerrit
-
-    CLI Examples:
-
-    .. code-block:: bash
-
-        salt '*' gerrit.project_create namespace/nova description='nova project'
-        salt '*' gerrit.project_create namespace/test enabled=False
-    
-    '''
-    ret = {}
-    gerrit = auth(**kwargs)
-
-    project = _get_project(gerrit, name)
-
-    if project and not "Error" in project:
-        LOG.debug("Project {0} exists".format(name))
-        ret[project.get('path_with_namespace')] = project
-        return ret
-
-    group_name, name = name.split('/')
-    group = group_get(name=group_name)[group_name]
-    kwargs['namespace_id'] = group.get('id')
-    kwargs['name'] = name
-    LOG.debug(kwargs)
-
-    new = gerrit.createproject(**kwargs)
-    if not new:
-        return {'Error': 'Error creating project %s' % new}
-    else:
-        LOG.debug(new)
-        ret[new.get('path_with_namespace')] = new
-        return ret
-
-def project_delete(project, **kwargs):
-    '''
-    Delete a project (gerrit project-delete)
-
-    :params project: Name or ID
-
-    CLI Examples:
-
-    .. code-block:: bash
-
-        salt '*' gerrit.project_delete c965f79c4f864eaaa9c3b41904e67082
-        salt '*' gerrit.project_delete project_id=c965f79c4f864eaaa9c3b41904e67082
-        salt '*' gerrit.project_delete name=demo
-    '''
-    gerrit = auth(**kwargs)
-
-    project = _get_project(gerrit, project)
-
-    if not project:
-        return {'Error': 'Unable to resolve project'}
-
-    del_ret = gerrit.deleteproject(project["id"])
-    ret = 'Project ID {0} deleted'.format(project["path_with_namespace"])
-    ret += ' ({0})'.format(project["path_with_namespace"])
-
-    return ret
-
-
-def project_get(project_id=None, name=None, **kwargs):
-    '''
-    Return a specific project
-
-    CLI Examples:
-
-    .. code-block:: bash
-
-        salt '*' gerrit.project_get 323
-        salt '*' gerrit.project_get project_id=323
-        salt '*' gerrit.project_get name=namespace/repository
-    '''
-    gerrit = auth(**kwargs)
-    ret = {}
-    #object_list = project_list(kwargs)
-
-    project = _get_project(gerrit, name or project_id)
-    if not project:
-        return {'Error': 'Error in retrieving project'}
-    ret[project.get('name')] = project
-    return ret
-
-
-def project_list(**connection_args):
-    '''
-    Return a list of available projects
-
-    CLI Example:
-
-    .. code-block:: bash
-
-        salt '*' gerrit.project_list
-    '''
-    gerrit = auth(**connection_args)
-    ret = {}
-
-    projects = gerrit.listProjects()
-
-    while len(projects) > 0:
-        for project in projects:
-            ret[project.get('path_with_namespace')] = project
-        page += 1
-        projects = gerrit.getprojectsall(page=page, per_page=PER_PAGE)
-    return ret
-
-
-def group_list(group_name=None, **connection_args):
-    '''
-    Return a list of available groups
-
-    CLI Example:
-
-    .. code-block:: bash
-
-        salt '*' gerrit.group_list
-    '''
-    gerrit = auth(**connection_args)
-    ret = {}
-    for group in gerrit.listProjects():
-        ret[group.get('name')] = group
-    return ret
-
-
-def group_get(id=None, name=None, **connection_args):
-    '''
-    Return a specific group
-
-    CLI Examples:
-
-    .. code-block:: bash
-
-        salt '*' gerrit.group_get 323
-        salt '*' gerrit.group_get name=namespace
-
-    '''
-    gerrit = auth(**connection_args)
-    ret = {}
-    if id == None:
-        for group in gerrit.getgroups(group_id=None, page=1, per_page=100):
-            if group.get('path') == name or group.get('name') == name:
-                ret[group.get('path')] = group
-    else:
-        group = gerrit.getgroups(id)
-        if group != False:
-            ret[group.get('path')] = group
-    if len(ret) == 0:
-        return {'Error': 'Error in retrieving group'}
-    return ret
-
diff --git a/gerrit/client.sls b/gerrit/client.sls
new file mode 100644
index 0000000..be7d39b
--- /dev/null
+++ b/gerrit/client.sls
@@ -0,0 +1,25 @@
+{% from "gerrit/map.jinja" import client with context %}
+{%- if client.enabled %}
+
+gerrit_client_install:
+  pkg.installed:
+  - names: {{ client.pkgs }}
+
+/etc/salt/minion.d/_gerrit.conf:
+  file.managed:
+  - source: salt://gerrit/files/_gerrit.conf
+  - template: jinja
+
+/var/cache/salt/minion/gerrit_rsa:
+  file.managed:
+  - contents_pillar: gerrit:client:server:key
+
+{%- for project_name, project in client.project.iteritems() %}
+
+gerrit_client_project_{{ project_name }}:
+  gerrit.project_present:
+  - name: {{ project_name }}
+
+{%- endfor %}
+
+{%- endif %}
diff --git a/gerrit/files/_gerrit.conf b/gerrit/files/_gerrit.conf
new file mode 100644
index 0000000..76abb70
--- /dev/null
+++ b/gerrit/files/_gerrit.conf
@@ -0,0 +1,7 @@
+{%- from "gerrit/map.jinja" import client with context %}
+gerrit:
+  host: {{ client.server.host }}
+  {%- if client.server.user is defined %}
+  user: {{ client.server.user }}
+  keyfile: /var/cache/salt/minion/gerrit_rsa
+  {%- endif %}
\ No newline at end of file
diff --git a/gerrit/init.sls b/gerrit/init.sls
index 0fb21bf..f89cd94 100644
--- a/gerrit/init.sls
+++ b/gerrit/init.sls
@@ -3,4 +3,7 @@
 {%- if pillar.gerrit.server is defined %}
 - gerrit.server
 {%- endif %}
+{%- if pillar.gerrit.client is defined %}
+- gerrit.client
+{%- endif %}
 {%- endif %}
diff --git a/gerrit/map.jinja b/gerrit/map.jinja
index b72f407..07ee440 100644
--- a/gerrit/map.jinja
+++ b/gerrit/map.jinja
@@ -1,5 +1,5 @@
 
-{%- load_yaml as base_defaults %}
+{%- load_yaml as server_defaults %}
 Debian:
   pkgs:
   - unzip
@@ -11,4 +11,12 @@
   reindex_threads: 1
 {%- endload %}
 
-{%- set server = salt['grains.filter_by'](base_defaults, merge=salt['pillar.get']('gerrit:server')) %}
+{%- set server = salt['grains.filter_by'](server_defaults, merge=salt['pillar.get']('gerrit:server')) %}
+
+{%- load_yaml as client_defaults %}
+Debian:
+  pkgs:
+  - python-gerritlib
+{%- endload %}
+
+{%- set client = salt['grains.filter_by'](client_defaults, merge=salt['pillar.get']('gerrit:client')) %}