Merge pull request #12 from tcpcloud/meta

jenkins service metadata
diff --git a/README.rst b/README.rst
index a83d61f..1d20ec7 100644
--- a/README.rst
+++ b/README.rst
@@ -306,6 +306,65 @@
             - repository: base
               file: macros/git.groovy
 
+SMTP server settings
+
+.. code-block:: yaml
+
+    jenkins:
+      master:
+        email:
+          engine: "smtp"
+          host: "smtp.domain.com"
+          user: "user@domain.cz"
+          password: "smtp-password"
+          port: 25
+
+Jenkins script approvals
+
+.. code-block:: yaml
+    
+    jenkins:
+      master:
+        approved_scripts:
+        - method groovy.json.JsonSlurperClassic parseText java.lang.String
+
+Credentials enforcing
+
+.. code-block:: yaml
+    
+    jenkins:
+      master:
+        credentials:
+          - type: username_password
+            scope: GLOBAL
+            id: credential-1
+            desc: ""
+            username: admin
+            password: "password"
+          - type: ssh_key
+            scope: GLOBAL
+            id: key-credential
+            desc: ""
+            username: admin
+            password: "key-password"
+            key: |
+               xxxxxxxxxxxxxxxxxxxx
+
+Users enforcing 
+
+.. code-block:: yaml
+
+    jenkins:
+      user:
+        admin:
+          api_token: xxxxxxxxxx
+          password: admin_password
+          email: admin@domain.com
+        user01:
+          api_token: xxxxxxxxxx
+          password: user_password
+          email: user01@domain.com
+
 Usage
 =====
 
diff --git a/_modules/jenkins_hash.py b/_modules/jenkins_hash.py
new file mode 100644
index 0000000..cf9a9d6
--- /dev/null
+++ b/_modules/jenkins_hash.py
@@ -0,0 +1,6 @@
+import bcrypt
+
+
+def encode_password(password):
+    if isinstance(password, str):
+        return bcrypt.hashpw(password, bcrypt.gensalt(prefix=b"2a"))
diff --git a/jenkins/files/_jenkins.conf b/jenkins/files/_jenkins.conf
index 42cf6fd..3461e87 100644
--- a/jenkins/files/_jenkins.conf
+++ b/jenkins/files/_jenkins.conf
@@ -1,7 +1,9 @@
 {%- from "jenkins/map.jinja" import client with context %}
 jenkins:
   url: "{{ client.master.get('proto', 'http') }}://{{ client.master.host }}:{{ client.master.port }}"
-  {%- if client.master.username is defined %}
+  {%- if client.master.api_key is defined %}
+  api_key: {{ client.master.api_key }}
+  {%- elif client.master.username is defined %}
   user: {{ client.master.username }}
   password: {{ client.master.password }}
   {%- endif %}
\ No newline at end of file
diff --git a/jenkins/files/config.xml.user b/jenkins/files/config.xml.user
index 9d442a4..b28a87f 100644
--- a/jenkins/files/config.xml.user
+++ b/jenkins/files/config.xml.user
@@ -1,4 +1,4 @@
-{%- set user = salt['pillar.get']('jenkins:master:user:'+user_name) -%}
+{%- set user = pillar.jenkins.master.user.get(user_name) -%}
 <?xml version='1.0' encoding='UTF-8'?>
 <user>
   <fullName>admin</fullName>
@@ -6,9 +6,11 @@
     <hudson.model.PaneStatusProperties>
       <collapsed/>
     </hudson.model.PaneStatusProperties>
+    {%- if user.api_token is defined %}
     <jenkins.security.ApiTokenProperty>
       <apiToken>{{ user.api_token }}</apiToken>
     </jenkins.security.ApiTokenProperty>
+    {%- endif %}
     <com.cloudbees.plugins.credentials.UserCredentialsProvider_-UserCredentialsProperty plugin="credentials@1.9.4">
       <domainCredentialsMap class="hudson.util.CopyOnWriteMap$Hash"/>
     </com.cloudbees.plugins.credentials.UserCredentialsProvider_-UserCredentialsProperty>
@@ -27,7 +29,7 @@
       <insensitiveSearch>false</insensitiveSearch>
     </hudson.search.UserSearchProperty>
     <hudson.security.HudsonPrivateSecurityRealm_-Details>
-      <passwordHash>{{ user.password_hash }}</passwordHash>
+      <passwordHash>#jbcrypt:{{ salt['jenkins_hash.encode_password'](user.password) }}</passwordHash>
     </hudson.security.HudsonPrivateSecurityRealm_-Details>
     {%- if user.public_keys is defined %}
     <org.jenkinsci.main.modules.cli.auth.ssh.UserPropertyImpl>
@@ -39,4 +41,4 @@
       <emailAddress>{{ user.get("email", "root@local.domain") }}</emailAddress>
     </hudson.tasks.Mailer_-UserProperty>
   </properties>
-</user>
\ No newline at end of file
+</user>
diff --git a/jenkins/files/credentials.xml b/jenkins/files/credentials.xml
index 8e3da7b..fc6c244 100644
--- a/jenkins/files/credentials.xml
+++ b/jenkins/files/credentials.xml
@@ -14,7 +14,7 @@
                 <id>{{ credential.id }}</id>
                 <description>{{ credential.desc }}</description>
                 <username>{{ credential.username }}</username>
-                <password>{{ credential.password_hash }}</password>
+                <password>{{ salt['jenkins_hash.encode_password'](credential.password) }}</password>
             </com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>
             {%- elif credential.type == "ssh_key" %}
             <com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey plugin="ssh-credentials@1.12">
@@ -22,7 +22,9 @@
                 <id>{{ credential.id }}</id>
                 <description>{{ credential.desc }}</description>
                 <username>{{ credential.username }}</username>
-                <passphrase>{{ credential.password_hash }}</passphrase>
+                {%- if credential.password is defined %}
+                <passphrase>{{ salt['jenkins_hash.encode_password'](credential.password) }}</passphrase>
+                {%- endif %}
                 <privateKeySource class="com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource">
                     <privateKey>{{ credential.key }}</privateKey>
                 </privateKeySource>
diff --git a/jenkins/files/hudson.tasks.Mailer.xml b/jenkins/files/hudson.tasks.Mailer.xml
index ab60d4d..00c146d 100644
--- a/jenkins/files/hudson.tasks.Mailer.xml
+++ b/jenkins/files/hudson.tasks.Mailer.xml
@@ -3,7 +3,7 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <hudson.tasks.Mailer_-DescriptorImpl plugin="mailer@1.18">
   <smtpAuthUsername>{{ master.email.user }}</smtpAuthUsername>
-  <smtpAuthPassword>{{ master.email.password_hash }}</smtpAuthPassword>
+  <smtpAuthPassword>{{ salt['jenkins_hash.encode_password'](master.email.password) }}</smtpAuthPassword>
   <smtpHost>{{ master.email.host }}</smtpHost>
   <useSsl>false</useSsl>
   <smtpPort>{{ master.email.port }}</smtpPort>
diff --git a/jenkins/map.jinja b/jenkins/map.jinja
index eb8fbbc..27c33bd 100644
--- a/jenkins/map.jinja
+++ b/jenkins/map.jinja
@@ -1,7 +1,7 @@
 
 {% set master = salt['grains.filter_by']({
     'Debian': {
-        'pkgs': ['jenkins'],
+        'pkgs': ['jenkins','python-bcrypt'],
         'service': 'jenkins',
         'config': '/etc/default/jenkins',
         'home': '/var/lib/jenkins',
diff --git a/jenkins/master/plugin.sls b/jenkins/master/plugin.sls
index 7eb8403..f260045 100644
--- a/jenkins/master/plugin.sls
+++ b/jenkins/master/plugin.sls
@@ -8,19 +8,23 @@
 setup_jenkins_cli:
   cmd.run:
   - names:
-    - sleep 30
     - wget http://localhost:{{ master.http.port }}/jnlpJars/jenkins-cli.jar
   - unless: "[ -f /root/jenkins-cli.jar ]"
   - cwd: /root
+  - require:
+    - cmd: jenkins_service_running
 
 {%- for plugin in master.plugins %}
 
 install_jenkins_plugin_{{ plugin.name }}:
   cmd.run:
-  - name: java -jar jenkins-cli.jar -s http://localhost:{{ master.http.port }} install-plugin --username admin --password {{ master.user.admin.password }} {{ plugin.name }}
+  - name: >
+      java -jar jenkins-cli.jar -s http://localhost:{{ master.http.port }} install-plugin {{ plugin.name }} ||
+      java -jar jenkins-cli.jar -s http://localhost:{{ master.http.port }} install-plugin --username admin --password {{ master.user.admin.password }} {{ plugin.name }}
   - unless: "[ -d {{ master.home }}/plugins/{{ plugin.name }} ]"
   - cwd: /root
   - require:
     - cmd: setup_jenkins_cli
+    - cmd: jenkins_service_running
 
 {%- endfor %}
diff --git a/jenkins/master/service.sls b/jenkins/master/service.sls
index fc053ff..d0925cb 100644
--- a/jenkins/master/service.sls
+++ b/jenkins/master/service.sls
@@ -20,15 +20,15 @@
   - require:
     - pkg: jenkins_packages
 
+{%- if master.get('no_config', False) == False %}
 {{ master.home }}/config.xml:
   file.managed:
-  {%- if master.get('no_config', False) == False %}
   - source: salt://jenkins/files/config.xml
   - template: jinja
-  {%- endif %}
   - user: jenkins
-  - require:
-    - pkg: jenkins_packages
+  - watch_in:
+    - service: jenkins_master_service
+{%- endif %}
 
 {%- if master.update_site_url is defined %}
 
@@ -97,7 +97,12 @@
   - name: {{ master.service }}
   - watch:
     - file: jenkins_{{ master.config }}
-    - file: {{ master.home }}/config.xml
     - file: {{ master.home }}/hudson.model.UpdateCenter.xml
 
+jenkins_service_running:
+  cmd.wait:
+    - name: "i=0; while true; do curl -s -f http://localhost:{{ master.http.port }} >/dev/null && exit 0; [ $i -gt 60 ] && exit 1; sleep 5; done"
+    - watch:
+      - service: jenkins_master_service
+
 {%- endif %}
diff --git a/jenkins/master/user.sls b/jenkins/master/user.sls
index 1c262ce..d8df637 100644
--- a/jenkins/master/user.sls
+++ b/jenkins/master/user.sls
@@ -16,5 +16,11 @@
       user_name: "{{ user_name }}"
   - watch_in:
     - service: jenkins_master_service
+  - unless: test -e {{ master.home }}/users/{{ user_name }}/.config_created
+
+{{ master.home }}/users/{{ user_name }}/.config_created:
+  file.touch:
+  - require:
+    - file: {{ master.home }}/users/{{ user_name }}/config.xml
 
 {%- endfor %}
diff --git a/jenkins/meta/config.yml b/jenkins/meta/config.yml
index db12201..d54cf0b 100644
--- a/jenkins/meta/config.yml
+++ b/jenkins/meta/config.yml
@@ -37,6 +37,15 @@
     template: jinja
   {%- endif %}
 
+  {%- for user_name, user in master.get('user', {}).iteritems() %}
+  {{ user_name }}_config.yml:
+    path: {{ master.home }}/users/{{ user_name }}/config.xml
+    source: "salt://jenkins/files/config.xml.user"
+    template: jinja
+    defaults:
+      user_name: "{{ user_name }}"
+  {%- endfor %}
+
   {%- endif %}
 
 
diff --git a/metadata/service/master/single.yml b/metadata/service/master/single.yml
index c93864a..3a8a82e 100644
--- a/metadata/service/master/single.yml
+++ b/metadata/service/master/single.yml
@@ -16,5 +16,4 @@
         admin:
           api_token: ${_param:jenkins_admin_token}
           password: ${_param:jenkins_admin_password}
-          password_hash: ${_param:jenkins_admin_password_hash}
           email: root@domain.com