Jenkins client for job enforcement
diff --git a/README.rst b/README.rst
index 237812c..b4bc7e6 100644
--- a/README.rst
+++ b/README.rst
@@ -13,17 +13,23 @@
``jenkins.master``
------------------
-Setup jenkins master
+Setup jenkins master.
``jenkins.slave``
-----------------
-Setup jenkins slave
+Setup jenkins slave.
``jenkins.job_builder``
-----------------------
-Setup jenkins job builder
+Setup jenkins job builder.
+
+``jenkins.client``
+------------------
+
+Setup jenkins client, works with Salt 2016.3+, supports pipeline workflow projects only now.
+
Available metadata
==================
@@ -42,10 +48,13 @@
Setup Jenkins slave
-Example pillars
-===============
+Sample pillars
+==============
Jenkins master
+--------------
+
+Simple master with reverse proxy
.. code-block:: yaml
@@ -89,7 +98,8 @@
- name: rebuild
- name: test-stability
-Jenkins slave
+Agent (former slave)
+--------------------
.. code-block:: yaml
@@ -110,6 +120,72 @@
private_key: |
-----BEGIN PGP PRIVATE KEY BLOCK-----
...
+Client
+------
+
+Simple client with workflow job definition
+
+.. code-block:: yaml
+
+ jenkins:
+ client:
+ master:
+ host: jenkins.example.com
+ port: 80
+ protocol: http
+ job:
+ jobname:
+ type: workflow
+ param:
+ bool_param:
+ type: boolean
+ description: true/false
+ default: true
+ string_param:
+ type: string
+ description: 1 liner
+ default: default_string
+ text_param:
+ type: text
+ description: multi-liner
+ default: default_text
+
+Groovy script samples
+
+.. code-block:: yaml
+
+ jenkins:
+ client:
+ job:
+ test_workflow_jenkins_simple:
+ type: workflow
+ display_name: Test jenkins simple workflow
+ script: |
+ node {
+ stage 'Stage 1'
+ echo 'Hello World 1'
+ stage 'Stage 2'
+ echo 'Hello World 2'
+ }
+ test_workflow_jenkins_input:
+ type: workflow
+ display_name: Test jenkins workflow inputs
+ script: |
+ node {
+ stage 'Enter string'
+ input message: 'Enter job parameters', ok: 'OK', parameters: [
+ string(defaultValue: 'default', description: 'Enter a string.', name: 'string'),
+ ]
+ stage 'Enter boolean'
+ input message: 'Enter job parameters', ok: 'OK', parameters: [
+ booleanParam(defaultValue: false, description: 'Select boolean.', name: 'Bool'),
+ ]
+ stage 'Enter text'
+ input message: 'Enter job parameters', ok: 'OK', parameters: [
+ text(defaultValue: '', description: 'Enter multiline', name: 'Multiline')
+ ]
+ }
+
Usage
=====
diff --git a/jenkins/client.sls b/jenkins/client.sls
new file mode 100644
index 0000000..8bb0010
--- /dev/null
+++ b/jenkins/client.sls
@@ -0,0 +1,40 @@
+{% from "jenkins/map.jinja" import client with context %}
+{%- if client.enabled %}
+
+jenkins_client_install:
+ pkg.installed:
+ - names: {{ client.pkgs }}
+
+jenkins_client_dirs:
+ file.directory:
+ - name: /srv/salt/env/dev/_jenkins_jobs
+ - makedirs: true
+
+/etc/salt/minion.d/_jenkins.conf:
+ file.managed:
+ - source: salt://jenkins/files/_jenkins.conf
+ - template: jinja
+
+{%- for job_name, job in client.job.iteritems() %}
+
+/srv/salt/env/dev/_jenkins_jobs/{{ job_name }}.xml:
+ file.managed:
+ - source: salt://jenkins/files/jobs/{{ job.type }}.xml
+ - mode: 400
+ - template: jinja
+ - defaults:
+ job_name: {{ job_name }}
+ - require:
+ - file: jenkins_client_dirs
+ - file: /etc/salt/minion.d/_jenkins.conf
+
+jenkins_job_{{ job_name }}_ensure:
+ jenkins.present:
+ - name: {{ job_name }}
+ - config: salt://_jenkins_jobs/{{ job_name }}.xml
+ - require:
+ - file: /srv/salt/env/dev/_jenkins_jobs/{{ job_name }}.xml
+
+{%- endfor %}
+
+{%- endif %}
diff --git a/jenkins/files/_jenkins.conf b/jenkins/files/_jenkins.conf
new file mode 100644
index 0000000..4d716a1
--- /dev/null
+++ b/jenkins/files/_jenkins.conf
@@ -0,0 +1,5 @@
+{%- from "jenkins/map.jinja" import client with context %}
+jenkins:
+ url: "{{ client.master.get('proto', 'http') }}://{{ client.master.host }}:{{ client.master.port }}"
+ user: {{ client.master.username }}
+ password: {{ client.master.password }}
\ No newline at end of file
diff --git a/jenkins/files/jobs/workflow.xml b/jenkins/files/jobs/workflow.xml
new file mode 100644
index 0000000..9b10270
--- /dev/null
+++ b/jenkins/files/jobs/workflow.xml
@@ -0,0 +1,43 @@
+{%- from "jenkins/map.jinja" import client with context %}
+{%- set job = salt['pillar.get']('jenkins:client:job:'+job_name) -%}
+<?xml version='1.0' encoding='UTF-8'?>
+<flow-definition plugin="workflow-job@2.5">
+ <description>{{ job.get('description', 'Salt generated, do not edit.') }}</description>
+ {%- if job.display_name is defined %}
+ <displayName>{{ job.display_name }}</displayName>
+ {%- endif %}
+ <keepDependencies>false</keepDependencies>
+ <properties>
+ <org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
+ <triggers/>
+ </org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
+ {%- if job.param is defined %}
+ <hudson.model.ParametersDefinitionProperty>
+ <parameterDefinitions>
+ {%- for param_name, param in job.param.iteritems() %}
+ <hudson.model.{{ client.param[param.type] }}ParameterDefinition>
+ <name>{{ param_name }}</name>
+ <description>{{ param.get('description', '')|e }}</description>
+ {%- if param.type == "choice" %}
+ <choices class="java.util.Arrays$ArrayList">
+ <a class="string-array">
+ {%- for choice in param.choices %}
+ <string>{{ choice|e }}</string>
+ {%- endfor %}
+ </a>
+ </choices>
+ {%- endif %}
+ <defaultValue>{{ param.default|e }}</defaultValue>
+ </hudson.model.{{ client.param[param.type] }}ParameterDefinition>
+ {%- endfor %}
+ </parameterDefinitions>
+ </hudson.model.ParametersDefinitionProperty>
+ {%- endif %}
+ </properties>
+ <definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition" plugin="workflow-cps@2.12">
+ <script>{{ job.script|e }}</script>
+ <sandbox>true</sandbox>
+ </definition>
+ <triggers>
+ </triggers>
+</flow-definition>
diff --git a/jenkins/init.sls b/jenkins/init.sls
index 985416e..db523b2 100644
--- a/jenkins/init.sls
+++ b/jenkins/init.sls
@@ -1,11 +1,14 @@
include:
-{% if pillar.jenkins.master is defined %}
+{%- if pillar.jenkins.master is defined %}
- jenkins.master
-{% endif %}
-{% if pillar.jenkins.job_builder is defined %}
-- jenkins.job_builder
-{% endif %}
-{% if pillar.jenkins.slave is defined %}
+{%- endif %}
+{%- if pillar.jenkins.slave is defined %}
- jenkins.slave
-{% endif %}
+{%- if pillar.jenkins.job_builder is defined %}
+- jenkins.job_builder
+{%- endif %}
+{%- if pillar.jenkins.client is defined %}
+- jenkins.client
+{%- endif %}
+{%- endif %}
diff --git a/jenkins/map.jinja b/jenkins/map.jinja
index bbcf637..7336d88 100644
--- a/jenkins/map.jinja
+++ b/jenkins/map.jinja
@@ -57,3 +57,16 @@
'config': '/etc/sysconfig/jenkins-slave',
},
}, merge=salt['pillar.get']('jenkins:slave')) %}
+
+{% set param = {'bool': 'Boolean', 'string': 'String', 'text': 'Text'} %}
+
+{% set client = salt['grains.filter_by']({
+ 'Debian': {
+ 'pkgs': ['python-jenkins'],
+ 'param': param,
+ },
+ 'RedHat': {
+ 'pkgs': ['python-jenkins'],
+ 'param': param,
+ },
+}, merge=salt['pillar.get']('jenkins:client')) %}
diff --git a/jenkins/master/init.sls b/jenkins/master/init.sls
index d67eab6..7ee07ba 100644
--- a/jenkins/master/init.sls
+++ b/jenkins/master/init.sls
@@ -2,8 +2,8 @@
{%- if master.enabled %}
include:
- jenkins.master.service
-- jenkins.master.users
+- jenkins.master.user
{%- if master.plugins is defined %}
-- jenkins.master.plugins
+- jenkins.master.plugin
{%- endif %}
{%- endif %}
diff --git a/jenkins/master/plugins.sls b/jenkins/master/plugin.sls
similarity index 100%
rename from jenkins/master/plugins.sls
rename to jenkins/master/plugin.sls
diff --git a/jenkins/master/users.sls b/jenkins/master/user.sls
similarity index 100%
rename from jenkins/master/users.sls
rename to jenkins/master/user.sls
diff --git a/metadata/service/vendor_repo/stable_debian.yml b/metadata/service/vendor_repo/stable_debian.yml
new file mode 100644
index 0000000..bd2b8e8
--- /dev/null
+++ b/metadata/service/vendor_repo/stable_debian.yml
@@ -0,0 +1,8 @@
+parameters:
+ linux:
+ system:
+ repo:
+ jenkins:
+ enabled: true
+ source: 'deb http://pkg.jenkins.io/debian-stable binary/'
+ key_url: 'http://pkg.jenkins.io/debian-stable/jenkins.io.key'