Merge pull request #3 from tcpcloud/client_jobs
Jenkins client for job enforcement
diff --git a/README.rst b/README.rst
index 237812c..44fe5ba 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,18 @@
- name: rebuild
- name: test-stability
-Jenkins slave
+Jenkins with experimental plugin source support
+
+.. code-block:: yaml
+
+ jenkins:
+ master:
+ enabled: true
+ update_site_url: 'http://updates.jenkins-ci.org/experimental/update-center.json'
+
+
+Agent (former slave)
+--------------------
.. code-block:: yaml
@@ -111,6 +131,148 @@
-----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
+
+Inline Groovy script samples
+
+.. code-block:: yaml
+
+ jenkins:
+ client:
+ job:
+ test_workflow_jenkins_simple:
+ type: workflow
+ display_name: Test jenkins simple workflow
+ script:
+ content: |
+ 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:
+ content: |
+ 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')
+ ]
+ }
+
+
+GIT controlled groovy script samples
+
+.. code-block:: yaml
+
+ jenkins:
+ client:
+ source:
+ base:
+ engine: git
+ address: repo_url
+ branch: branch
+ domain:
+ engine: git
+ address: domain_url
+ branch: branch
+ job:
+ test_workflow_jenkins_simple:
+ type: workflow
+ display_name: Test jenkins simple workflow
+ param:
+ bool_param:
+ type: boolean
+ description: true/false
+ default: true
+ script:
+ repository: base
+ file: workflows/test_workflow_jenkins_simple.groovy
+ test_workflow_jenkins_input:
+ type: workflow
+ display_name: Test jenkins workflow inputs
+ script:
+ repository: domain
+ file: workflows/test_workflow_jenkins_input.groovy
+ test_workflow_jenkins_input_jenkinsfile:
+ type: workflow
+ display_name: Test jenkins workflow inputs (jenknisfile)
+ script:
+ repository: domain
+ file: workflows/test_workflow_jenkins_input/Jenkinsfile
+
+GIT controlled groovy script with shared libraries
+
+.. code-block:: yaml
+
+ jenkins:
+ client:
+ source:
+ base:
+ engine: git
+ address: repo_url
+ branch: branch
+ domain:
+ engine: git
+ address: domain_url
+ branch: branch
+ job:
+ test_workflow_jenkins_simple:
+ type: workflow
+ display_name: Test jenkins simple workflow
+ param:
+ bool_param:
+ type: boolean
+ description: true/false
+ default: true
+ script:
+ repository: base
+ file: workflows/test_workflow_jenkins_simple.groovy
+ libs:
+ - repository: base
+ file: macros/cookiecutter.groovy
+ - repository: base
+ file: macros/git.groovy
+
Usage
=====
diff --git a/jenkins/client.sls b/jenkins/client.sls
new file mode 100644
index 0000000..0228894
--- /dev/null
+++ b/jenkins/client.sls
@@ -0,0 +1,68 @@
+{% from "jenkins/map.jinja" import client with context %}
+{%- if client.enabled %}
+
+jenkins_client_install:
+ pkg.installed:
+ - names: {{ client.pkgs }}
+
+jenkins_client_dirs:
+ file.directory:
+ - names:
+ - /srv/jenkins
+ - {{ client.dir.salt_root }}/_jenkins/cache
+ - makedirs: true
+
+/etc/salt/minion.d/_jenkins.conf:
+ file.managed:
+ - source: salt://jenkins/files/_jenkins.conf
+ - template: jinja
+
+{%- for source_name, source in client.source.iteritems() %}
+
+{%- if source.engine == "git" %}
+
+jenkins_{{ source_name }}_source:
+ git.latest:
+ - name: {{ source.address }}
+ - target: {{ client.dir.jenkins_root }}/{{ source_name }}
+ - rev: {{ source.branch }}
+ - reload_pillar: True
+
+{%- elif client.source.engine == "local" %}
+
+jenkins_{{ source_name }}_dir:
+ file.managed:
+ - name: {{ client.dir.jenkins_root }}/{{ source_name }}
+ - mode: 700
+
+{%- endif %}
+
+{%- endfor %}
+
+{{ client.dir.salt_root }}/_jenkins/jobs:
+ file.symlink:
+ - target: {{ client.dir.jenkins_root }}
+
+{%- for job_name, job in client.job.iteritems() %}
+
+{{ client.dir.salt_root }}/_jenkins/cache/{{ 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/cache/{{ job_name }}.xml
+ - require:
+ - file: {{ client.dir.salt_root }}/_jenkins/cache/{{ job_name }}.xml
+
+{%- endfor %}
+
+{%- endif %}
diff --git a/jenkins/files/_jenkins.conf b/jenkins/files/_jenkins.conf
new file mode 100644
index 0000000..42cf6fd
--- /dev/null
+++ b/jenkins/files/_jenkins.conf
@@ -0,0 +1,7 @@
+{%- 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 %}
+ user: {{ client.master.username }}
+ password: {{ client.master.password }}
+ {%- endif %}
\ No newline at end of file
diff --git a/jenkins/files/hudson.model.UpdateCenter.xml b/jenkins/files/hudson.model.UpdateCenter.xml
new file mode 100644
index 0000000..72a1189
--- /dev/null
+++ b/jenkins/files/hudson.model.UpdateCenter.xml
@@ -0,0 +1,8 @@
+{%- from "jenkins/map.jinja" import server with context %}
+<?xml version='1.0' encoding='UTF-8'?>
+<sites>
+ <site>
+ <id>default</id>
+ <url>{{ server.update_site_url }}</url>
+ </site>
+</sites>
\ 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..aab96e8
--- /dev/null
+++ b/jenkins/files/jobs/workflow.xml
@@ -0,0 +1,69 @@
+<?xml version='1.0' encoding='UTF-8'?>
+{%- from "jenkins/map.jinja" import client with context -%}
+{%- set job = salt['pillar.get']('jenkins:client:job:'+job_name) -%}
+{%- macro load_groovy_file() %}
+{%- set groovy_file='_jenkins/jobs/'+job.script.repository+'/'+job.script.file %}
+{%- include groovy_file %}
+{%- endmacro %}
+{%- macro load_groovy_lib(lib) %}
+{%- set groovy_file='_jenkins/jobs/'+lib.repository+'/'+lib.file %}
+{%- include groovy_file %}
+{%- endmacro %}
+<flow-definition plugin="workflow-job@2.5">
+ <description>
+ Salt generated project, do not edit. Changes will be overwritten.
+ {{ job.get('description', '')|e }}
+ </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 %}
+ {%- if param.default is defined %}
+ <defaultValue>{{ param.default|e }}</defaultValue>
+ {%- endif %}
+ </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>// libraries
+{%- if job.libs is defined %}
+{%- for lib in job.libs %}
+{{ load_groovy_lib(lib)|e }}
+{%- endfor %}
+{%- endif %}
+// workflow
+
+{%- if job.script.file is defined %}
+{{ load_groovy_file()|e }}
+{%- else %}
+{{ job.script.get('content', '')|e }}
+{%- endif %}
+ </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..27e57ba 100644
--- a/jenkins/map.jinja
+++ b/jenkins/map.jinja
@@ -4,11 +4,13 @@
'pkgs': ['jenkins'],
'service': 'jenkins',
'config': '/etc/default/jenkins',
+ 'update_site_url': 'http://updates.jenkins-ci.org/update-center.json'
},
'RedHat': {
'pkgs': ['jenkins'],
'service': 'jenkins',
'config': '/etc/sysconfig/jenkins',
+ 'update_site_url': 'http://updates.jenkins-ci.org/update-center.json'
},
}, merge=salt['pillar.get']('jenkins:master')) %}
@@ -57,3 +59,24 @@
'config': '/etc/sysconfig/jenkins-slave',
},
}, merge=salt['pillar.get']('jenkins:slave')) %}
+
+{% set param = {'bool': 'Boolean', 'string': 'String', 'text': 'Text', 'choice': 'Choice'} %}
+
+{% set client = salt['grains.filter_by']({
+ 'Debian': {
+ 'pkgs': ['python-jenkins'],
+ 'param': param,
+ 'dir': {
+ 'salt_root': '/srv/salt/env/dev',
+ 'jenkins_root': '/srv/jenkins/client',
+ }
+ },
+ 'RedHat': {
+ 'pkgs': ['python-jenkins'],
+ 'param': param,
+ 'dir': {
+ 'salt_root': '/srv/salt/env/dev',
+ 'jenkins_root': '/srv/jenkins/client',
+ }
+ },
+}, 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 93%
rename from jenkins/master/plugins.sls
rename to jenkins/master/plugin.sls
index 49fb6a0..6c618e9 100644
--- a/jenkins/master/plugins.sls
+++ b/jenkins/master/plugin.sls
@@ -12,8 +12,6 @@
- wget http://localhost:{{ master.http.port }}/jnlpJars/jenkins-cli.jar
- unless: "[ -f /root/jenkins-cli.jar ]"
- cwd: /root
- - require:
- - service: jenkins_master_service
{%- for plugin in master.plugins %}
diff --git a/jenkins/master/service.sls b/jenkins/master/service.sls
index 5145844..d01a001 100644
--- a/jenkins/master/service.sls
+++ b/jenkins/master/service.sls
@@ -27,7 +27,14 @@
- template: jinja
{%- endif %}
- user: jenkins
- - group: nogroup
+ - require:
+ - pkg: jenkins_packages
+
+/var/lib/jenkins/hudson.model.UpdateCenter.xml:
+ file.managed:
+ - source: salt://jenkins/files/hudson.model.UpdateCenter.xml
+ - template: jinja
+ - user: jenkins
- require:
- pkg: jenkins_packages
@@ -51,5 +58,6 @@
- watch:
- file: jenkins_{{ master.config }}
- file: /var/lib/jenkins/config.xml
+ - file: /var/lib/jenkins/hudson.model.UpdateCenter.xml
{%- endif %}
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'