Enforcing accounts, users, passwords, keys
diff --git a/_modules/gerrit.py b/_modules/gerrit.py
index 64d62ad..c067cfd 100644
--- a/_modules/gerrit.py
+++ b/_modules/gerrit.py
@@ -62,29 +62,6 @@
 __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
-
-
 # COMMON
 
 
@@ -189,10 +166,38 @@
         changed = True
     return value, changed
 
+
+def quote(name):
+    return urllib.quote(name, safe="")
+
+
 # END COMMON
 
 
-def gerrit_connection(**connection_args):
+def _gerrit_ssh_connection(**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 _gerrit_http_connection(**connection_args):
 
     prefix = "gerrit"
 
@@ -203,21 +208,41 @@
             __salt__['config.get'](prefix, {})).get(key, default)
 
     host = get('host', 'localhost')
+    http_port = get('http_port', '8082')
+    protocol = get('protocol', 'http')
     username = get('user', 'admin')
     password = get('password', 'admin')
 
+    url = protocol+"://"+str(host)+':'+str(http_port)
+
     auth = requests.auth.HTTPDigestAuth(
         username, password)
 
     gerrit = pygerrit.rest.GerritRestAPI(
-        url=host, auth=auth)
+        url=url, auth=auth)
 
     return gerrit
 
 
+def _name2id(gerrit, username=None):
+    # Although we could pass an AccountInput entry here to set details in one
+    # go, it's left up to the _update_group() function, to avoid having a
+    # totally separate code path for create vs. update.
+    account_info = gerrit.put('/accounts/%s' % quote(username))
+    return account_info['_account_id']
+
+
+def _create_group(gerrit, name=None):
+    # Although we could pass an AccountInput entry here to set details in one
+    # go, it's left up to the _update_group() function, to avoid having a
+    # totally separate code path for create vs. update.
+    group_info = gerrit.put('/groups/%s' % quote(name))
+    return group_info
+
+
 def create_account(gerrit, username=None):
     # Although we could pass an AccountInput entry here to set details in one
-    # go, it's left up to the update_account() function, to avoid having a
+    # go, it's left up to the _update_account() function, to avoid having a
     # totally separate code path for create vs. update.
     account_info = gerrit.put('/accounts/%s' % quote(username))
     return account_info
@@ -348,7 +373,7 @@
     return ssh_public_key, changed
 
 
-def update_account(gerrit, username=None, **params):
+def _update_account(gerrit, username=None, **params):
     change = False
 
     try:
@@ -369,6 +394,7 @@
     path = 'accounts/%s' % account_id
 
     output = {}
+    output['username'] = username
     output['id'] = account_id
 
     fullname, fullname_changed = maybe_update_field(
@@ -376,7 +402,7 @@
     output['fullname'] = fullname
     change |= fullname_changed
 
-    # Ansible sets the value of params that the user did not provide to None.
+    # Set the value of params that the user did not provide to None.
 
     if params.get('active') is not None:
         active = get_boolean(gerrit, path + '/active')
@@ -391,11 +417,11 @@
         output['email'] = email
         change |= emails_changed
 
-    if params.get('groups') is not None:
-        groups, groups_changed = ensure_only_member_of_these_groups(
-            gerrit, account_id, params['groups'])
-        output['groups'] = groups
-        change |= groups_changed
+#    if params.get('groups') is not None:
+#        groups, groups_changed = ensure_only_member_of_these_groups(
+#            gerrit, account_id, params['groups'])
+#        output['groups'] = groups
+#        change |= groups_changed
 
     if params.get('http_password') is not None:
         http_password = get_string(gerrit, path + '/password.http')
@@ -415,10 +441,66 @@
     return output, change
 
 
-def user_create(username, fullname,
-                email, groups=[], **kwargs):
+def _update_group(gerrit, name=None, **params):
+    change = False
+
+    try:
+        group_info = gerrit.get('/groups/%s' % quote(name))
+    except requests.exceptions.HTTPError as e:
+        if e.response.status_code == 404:
+            logging.info("Group %s not found, creating it.", name)
+            group_info = _create_group(gerrit, name)
+            change = True
+        else:
+            raise
+
+    logging.debug(
+        'Existing info for group %s: %s', name,
+        json.dumps(group_info, indent=4))
+
+    output = {group_info['name']: group_info}
+
+    return output, change
+
+
+def account_create(username, fullname=None, email=None, active=None, groups=[], ssh_key=None, http_password=None, **kwargs):
     '''
-    Create a gerrit project
+    Create a gerrit account
+
+    :param username: username
+    :param fullname: fullname
+    :param email: email
+    :param active: active
+    :param groups: array of strings
+        groups:
+            - Non-Interactive Users
+            - Testers
+    :param ssh_key: public ssh key
+    :param http_password: http password
+
+    CLI Examples:
+
+    .. code-block:: bash
+
+        salt '*' gerrit.account_create username "full name" "mail@domain.com"
+
+    '''
+    gerrit_client = _gerrit_http_connection(**kwargs)
+    output, changed = _update_account(
+        gerrit_client, **{
+            'username': username,
+            'fullname': fullname,
+            'email': email,
+            'groups': groups,
+            'ssh_key': ssh_key,
+            'http_password': http_password
+        })
+    return output
+
+
+def account_update(username, fullname=None, email=None, active=None, groups=[], ssh_key=None, http_password=None, **kwargs):
+    '''
+    Create a gerrit account
 
     :param username: username
     :param fullname: fullname
@@ -427,26 +509,117 @@
         groups:
             - Non-Interactive Users
             - Testers
+    :param ssh_key: public ssh key
+    :param http_password: http password
+
     CLI Examples:
 
     .. code-block:: bash
 
-        salt '*' gerrit.user_create namespace/nova description='nova project'
+        salt '*' gerrit.account_create username "full name" "mail@domain.com"
 
     '''
-
-    gerrit_client = gerrit_connection(**kwargs)
-
-    output, changed = update_account(
+    gerrit_client = _gerrit_http_connection(**kwargs)
+    output, changed = _update_account(
         gerrit_client, **{
             'username': username,
             'fullname': fullname,
             'email': email,
             'groups': groups,
+            'ssh_key': ssh_key,
+            'http_password': http_password
         })
-
     return output
 
+def account_list(**kwargs):
+    '''
+    List gerrit accounts
+
+    CLI Examples:
+
+    .. code-block:: bash
+
+        salt '*' gerrit.account_list
+
+    '''
+    gerrit_client = _gerrit_http_connection(**kwargs)
+    ret_list = gerrit_client.get('/accounts/?q=*&n=10000')
+    ret = {}
+    for item in ret_list:
+        ret[item['username']] = item
+    return ret
+
+
+def account_get(username, **kwargs):
+    '''
+    Get gerrit account
+
+    CLI Examples:
+
+    .. code-block:: bash
+
+        salt '*' gerrit.account_get username
+
+    '''
+    gerrit_client = _gerrit_http_connection(**kwargs)
+    item, change = _update_account(gerrit_client, username, **{})
+    ret = item
+    return ret
+
+
+def group_list(**kwargs):
+    '''
+    List gerrit groups
+
+    CLI Examples:
+
+    .. code-block:: bash
+
+        salt '*' gerrit.group_list
+
+    '''
+    gerrit_client = _gerrit_http_connection(**kwargs)
+    return gerrit_client.get('/groups/')
+
+
+def group_get(groupname, **kwargs):
+    '''
+    Get gerrit group
+
+    CLI Examples:
+
+    .. code-block:: bash
+
+        salt '*' gerrit.group_get groupname
+
+    '''
+    gerrit_client = _gerrit_http_connection(**kwargs)
+    try: 
+        item = gerrit_client.get('/groups/%s' % groupname)
+        ret = {item['name']: item}
+    except:
+        ret = {'Error': 'Error in retrieving account'}
+    return ret
+
+
+def group_create(name, **kwargs):
+    '''
+    Create a gerrit group
+
+    :param name: name
+
+    CLI Examples:
+
+    .. code-block:: bash
+
+        salt '*' gerrit.group_create group-name
+
+    '''
+    gerrit_client = _gerrit_http_connection(**kwargs)
+    ret, changed = _update_group(
+        gerrit_client, **{'name': name})
+    return ret
+
 
 def project_create(name, **kwargs):
     '''
@@ -462,7 +635,7 @@
 
     '''
     ret = {}
-    gerrit_client = auth(**kwargs)
+    gerrit_client = _gerrit_ssh_connection(**kwargs)
 
     project = project_get(name, **kwargs)
 
@@ -484,9 +657,8 @@
 
         salt '*' gerrit.project_get projectname
     '''
-    gerrit_client = auth(**kwargs)
+    gerrit_client = _gerrit_ssh_connection(**kwargs)
     ret = {}
-
     projects = gerrit_client.listProjects()
     if not name in projects:
         return {'Error': 'Error in retrieving project'}
@@ -504,11 +676,9 @@
 
         salt '*' gerrit.project_list
     '''
-    gerrit_client = auth(**connection_args)
+    gerrit_client = _gerrit_ssh_connection(**connection_args)
     ret = {}
-
     projects = gerrit_client.listProjects()
-
     for project in projects:
         ret[project] = {
             'name': project
@@ -530,7 +700,7 @@
 
     '''
     ret = {}
-    gerrit_client = auth(**kwargs)
+    gerrit_client = _gerrit_ssh_connection(**kwargs)
     msg = gerrit_client.query(change)
     ret['query'] = msg
     return ret
diff --git a/_states/gerrit.py b/_states/gerrit.py
index 8bbdb77..d46a092 100644
--- a/_states/gerrit.py
+++ b/_states/gerrit.py
@@ -19,14 +19,74 @@
     '''
     Only load if the gerrit module is in __salt__
     '''
-    return 'gerrit' if 'gerrit.auth' in __salt__ else False
+    return 'gerrit' if 'gerrit.account_create' in __salt__ else False
+
+
+def account_present(username, fullname=None, email=None, active=None, groups=[], ssh_key=None, http_password=None, **kwargs):
+    '''
+    Ensures that the gerrit account exists
+    
+    :param username: username
+    :param fullname: fullname
+    :param email: email
+    :param active: active
+    :param groups: array of strings
+        groups:
+            - Non-Interactive Users
+            - Testers
+    :param ssh_key: public ssh key
+    :param http_password: http password
+
+    '''
+    ret = {'name': username,
+           'changes': {},
+           'result': True,
+           'comment': 'Account "{0}" already exists'.format(username)}
+
+    # Check if account is already present
+    group = __salt__['gerrit.account_get'](username, **kwargs)
+
+    if 'Error' not in group:
+        #update group
+        pass
+    else:
+        # Create group
+        __salt__['gerrit.project_create'](username, **kwargs)
+        ret['comment'] = 'Account "{0}" has been added'.format(username)
+        ret['changes']['Account'] = 'Created'
+    return ret
+
+
+def group_present(name, **kwargs):
+    '''
+    Ensures that the gerrit group exists
+    
+    :param name: group name
+    '''
+    ret = {'name': name,
+           'changes': {},
+           'result': True,
+           'comment': 'Group "{0}" already exists'.format(name)}
+
+    # Check if group is already present
+    group = __salt__['gerrit.group_get'](name=name, **kwargs)
+
+    if 'Error' not in group:
+        #update group
+        pass
+    else:
+        # Create group
+        __salt__['gerrit.project_create'](name, **kwargs)
+        ret['comment'] = 'Group "{0}" has been added'.format(name)
+        ret['changes']['Group'] = 'Created'
+    return ret
 
 
 def project_present(name, description=None, **kwargs):
     '''
     Ensures that the gerrit project exists
     
-    :param name: new project name
+    :param name: project name
     :param description: short project description
     '''
     ret = {'name': name,
diff --git a/gerrit/client/init.sls b/gerrit/client/init.sls
index 697240b..a05f9df 100644
--- a/gerrit/client/init.sls
+++ b/gerrit/client/init.sls
@@ -1,3 +1,3 @@
 include:
 - gerrit.client.service
-- gerrit.client.project
+- gerrit.client.user
diff --git a/gerrit/client/user.sls b/gerrit/client/user.sls
new file mode 100644
index 0000000..1c0ce5c
--- /dev/null
+++ b/gerrit/client/user.sls
@@ -0,0 +1,33 @@
+{% from "gerrit/map.jinja" import client with context %}
+{%- if client.enabled %}
+
+{%- for group_name in client.get('groups', []) %}
+
+gerrit_client_group_{{ group_name }}:
+  gerrit.group_present:
+  - name: {{ group_name }}
+
+{%- endfor %}
+
+{%- for account_name, account in client.get('user', {}).iteritems() %}
+
+gerrit_client_account_{{ account_name }}:
+  gerrit.account_present:
+  - name: {{ account_name }}
+  - fullname: {{ account.fullname }}
+  {%- if account.active is defined %}
+  - active: {{ account.active }}
+  {%- endif %}
+  {%- if account.http_password is defined %}
+  - http_password: {{ account.http_password }}
+  {%- endif %}
+  {%- if account.groups is defined %}
+  - groups:
+    {%- for group in account.groups %}
+    - {{ group }}
+    {% endfor %}
+  {%- endif %}
+
+{%- endfor %}
+
+{%- endif %}
diff --git a/gerrit/files/_gerrit.conf b/gerrit/files/_gerrit.conf
index 9b65641..85d04df 100644
--- a/gerrit/files/_gerrit.conf
+++ b/gerrit/files/_gerrit.conf
@@ -2,6 +2,12 @@
 gerrit:
   host: {{ client.server.host }}
   user: {{ client.server.user }}
+  {%- if client.server.protocol is defined %}
+  protocol: {{ client.server.protocol }}
+  {%- endif %}
+  {%- if client.server.http_port is defined %}
+  http_port: {{ client.server.http_port }}
+  {%- endif %}
   {%- if client.server.password is defined %}
   password: {{ client.server.password }}
   {%- endif %}