From 55f7ea3c405e5da44e58dfa9c6f7b8ac6293595b Mon Sep 17 00:00:00 2001 From: transcaffeine Date: Tue, 4 Feb 2025 17:27:12 +0100 Subject: [PATCH] WIP: feat(jenkins): add role to deploy jenkins --- README.md | 2 + playbooks/jenkins.yml | 6 +++ roles/jenkins/README.md | 3 ++ roles/jenkins/defaults/main/container.yml | 59 +++++++++++++++++++++++ roles/jenkins/defaults/main/main.yml | 17 +++++++ roles/jenkins/handlers/default.yml | 13 +++++ roles/jenkins/tasks/check.yml | 21 ++++++++ roles/jenkins/tasks/deploy-docker.yml | 40 +++++++++++++++ roles/jenkins/tasks/main.yml | 26 ++++++++++ roles/jenkins/templates/docker-passwd.j2 | 19 ++++++++ roles/jenkins/vars/main.yml | 8 +++ 11 files changed, 214 insertions(+) create mode 100644 playbooks/jenkins.yml create mode 100644 roles/jenkins/README.md create mode 100644 roles/jenkins/defaults/main/container.yml create mode 100644 roles/jenkins/defaults/main/main.yml create mode 100644 roles/jenkins/handlers/default.yml create mode 100644 roles/jenkins/tasks/check.yml create mode 100644 roles/jenkins/tasks/deploy-docker.yml create mode 100644 roles/jenkins/tasks/main.yml create mode 100644 roles/jenkins/templates/docker-passwd.j2 create mode 100644 roles/jenkins/vars/main.yml diff --git a/README.md b/README.md index c840862..e55c0cb 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,6 @@ ## Roles +- [jenkins](roles/jenkins/README.md): Deploy [jenkins](https://jenkins.io), the self-proclaimed 'leading open source automation server'. + ## License diff --git a/playbooks/jenkins.yml b/playbooks/jenkins.yml new file mode 100644 index 0000000..75cffe0 --- /dev/null +++ b/playbooks/jenkins.yml @@ -0,0 +1,6 @@ +--- +- name: Install and configure jenkins + hosts: "{{ jenkins_hosts | default('jenkins', true) }}" + become: "{{ jenkins_become | default(true, true) }}" + roles: + - role: finallycoffee.cicd.jenkins diff --git a/roles/jenkins/README.md b/roles/jenkins/README.md new file mode 100644 index 0000000..de149c7 --- /dev/null +++ b/roles/jenkins/README.md @@ -0,0 +1,3 @@ +# `finallycoffee.cicd.jenkins` ansible role + +Deploy and configure [Jenkins](https://jenkins.io) using ansible. diff --git a/roles/jenkins/defaults/main/container.yml b/roles/jenkins/defaults/main/container.yml new file mode 100644 index 0000000..ca72b26 --- /dev/null +++ b/roles/jenkins/defaults/main/container.yml @@ -0,0 +1,59 @@ +--- +jenkins_container_name: "jenkins" +jenkins_container_image: >-2 + {{ + [ + jenkins_container_image_repository, + jenkins_container_image_tag + | default( + jenkins_version + ( + ((jenkins_container_image_flavour is string) + and (jenkins_container_image_flavour | length > 0)) + | ternary( + '-' + jenkins_container_image_flavour | default('', true), + '' + ) + ), + true + ) + ] | join(':') + }} +jenkins_container_image_registry: docker.io +jenkins_container_image_namespace: jenkins +jenkins_container_image_name: jenkins +jenkins_container_image_repository: >-2 + {{ + [ + jenkins_container_image_registry | default([], true), + jenkins_container_image_namespace | default([], true), + jenkins_container_image_name + ] | flatten | join('/') + }} +jenkins_container_image_source: "pull" +jenkins_container_image_force_source: >-2 + {{ jenkins_container_image_tag | default(true, true) }} +jenkins_container_image_tag: ~ +jenkins_container_image_flavour: "jdk17" + +jenkins_container_env: ~ +jenkins_container_user: >-2 + {{ jenkins_user_uid }}:{{ jenkins_user_gid }} +jenkins_container_ports: ~ +jenkins_container_state: >-2 + {{ (jenkins_state == 'present') | ternary('started', 'absent') }} +jenkins_container_labels: + version: "{{ jenkins_container_image_tag | default(jenkins_version, true) }}" +jenkins_container_networks: ~ +jenkins_container_etc_hosts: ~ +jenkins_container_base_volumes: + - "{{ jenkins_home_path }}:{{ jenkins_container_home_path }}:rw" + - "{{ jenkins_etc_passwd_shim_path }}:/etc/passwd:ro" +jenkins_container_volumes: ~ +jenkins_container_all_volumes: >-2 + {{ jenkins_container_base_volumes | default([], true) + + jenkins_container_volumes | default([], true) }} +jenkins_container_restart_policy: "on-failure" + +# Determined by upstream image +jenkins_container_home_path: "/var/jenkins_home" +jenkins_container_tcp_listen_port: "8080" diff --git a/roles/jenkins/defaults/main/main.yml b/roles/jenkins/defaults/main/main.yml new file mode 100644 index 0000000..7399fb1 --- /dev/null +++ b/roles/jenkins/defaults/main/main.yml @@ -0,0 +1,17 @@ +--- +jenkins_user: "jenkins" +jenkins_user_is_system: true +jenkins_user_create_home: false +jenkins_versions: + lts: "2.479.3" + weekly: "2.496" +jenkins_version_channel: "lts" +jenkins_version: "{{ jenkins_versions[jenkins_version_channel] }}" + +jenkins_state: present +jenkins_deployment_method: docker + +jenkins_home_path: "/var/lib/jenkins" +jenkins_etc_passwd_shim_path: "/etc/jenkins/docker-passwd" +jenkins_user_uid: "{{ jenkins_user_info.uid }}" +jenkins_user_gid: "{{ jenkins_user_info.group }}" diff --git a/roles/jenkins/handlers/default.yml b/roles/jenkins/handlers/default.yml new file mode 100644 index 0000000..79aa3b2 --- /dev/null +++ b/roles/jenkins/handlers/default.yml @@ -0,0 +1,13 @@ +--- +- name: Restart jenkins container '{{ jenkins_container_name }}' + community.docker.docker_container: + name: "{{ jenkins_container_name }}" + state: "started" + restart: true + comparisons: + '*': "ignore" + when: + - jenkins_deployment_method == 'docker' + - jenkins_container_state == 'started' + listen: jenkins_restart + ignore_errors: "{{ ansible_check_mode }}" diff --git a/roles/jenkins/tasks/check.yml b/roles/jenkins/tasks/check.yml new file mode 100644 index 0000000..f48eea0 --- /dev/null +++ b/roles/jenkins/tasks/check.yml @@ -0,0 +1,21 @@ +--- +- name: Ensure 'jenkins_state' is valid + ansible.builtin.fail: + msg: >-2 + Unsupported jenkins_state '{{ jenkins_state }}'. + Supported values are: {{ jenkins_states | join(', ') }} + when: jenkins_state not in jenkins_states + +- name: Ensure 'jenkins_deployment_method' is valid + ansible.builtin.fail: + msg: >-2 + Unsupported jenkins_deployment_method '{{ jenkins_deployment_method }}'. + Supported values are: {{ jenkins_deployment_methods | join(', ') }} + when: jenkins_deployment_method not in jenkins_deployment_methods + +- name: Ensure 'jenkins_version_channel' is valid + ansible.builtin.fail: + msg: >-2 + Unsupported jenkins_version_channel '{{ jenkins_version_channel }}'. + Supported values are: {{ jenkins_version_channels | join(', ') }} + when: jenkins_version_channel not in jenkins_version_channels diff --git a/roles/jenkins/tasks/deploy-docker.yml b/roles/jenkins/tasks/deploy-docker.yml new file mode 100644 index 0000000..d608fb1 --- /dev/null +++ b/roles/jenkins/tasks/deploy-docker.yml @@ -0,0 +1,40 @@ +--- +- name: Ensure jenkins container image '{{ jenkins_container_image }}' is {{ jenkins_state }} + community.docker.docker_image: + name: "{{ jenkins_container_image }}" + state: "{{ jenkins_state }}" + source: "{{ jenkins_container_image_source }}" + force_source: "{{ jenkins_container_image_force_source }}" + +- name: Ensure jenkins configuration folder is created + ansible.builtin.file: + path: "{{ jenkins_etc_passwd_shim_path | dirname }}" + state: directory + mode: "0755" + owner: "root" + group: "root" + when: jenkins_state == 'present' + +- name: Ensure jenkins fake '/etc/passwd' is created + ansible.builtin.template: + src: "docker-passwd.j2" + dest: "{{ jenkins_etc_passwd_shim_path }}" + mode: "0644" + owner: "root" + group: "root" + when: jenkins_state == 'present' + notify: + - jenkins_restart + +- name: Ensure jenkins container '{{ jenkins_container_name }}' is {{ jenkins_container_state }} + community.docker.docker_container: + name: "{{ jenkins_container_name }}" + image: "{{ jenkins_container_image }}" + env: "{{ jenkins_container_env | default(omit, true) }}" + user: "{{ jenkins_container_user | default(omit, true) }}" + ports: "{{ jenkins_container_ports | default(omit, true) }}" + labels: "{{ jenkins_container_labels | default(omit, true) }}" + networks: "{{ jenkins_container_networks | default(omit, true) }}" + volumes: "{{ jenkins_container_all_volumes }}" + restart_policy: "{{ jenkins_container_restart_policy }}" + state: "{{ jenkins_container_state }}" diff --git a/roles/jenkins/tasks/main.yml b/roles/jenkins/tasks/main.yml new file mode 100644 index 0000000..bfe8680 --- /dev/null +++ b/roles/jenkins/tasks/main.yml @@ -0,0 +1,26 @@ +--- +- name: Ensure role arguments are valid + ansible.builtin.include_tasks: + file: "check.yml" + +- name: Ensure jenkins user '{{ jenkins_user }}' is {{ jenkins_state }} + ansible.builtin.user: + name: "{{ jenkins_user }}" + state: "{{ jenkins_state }}" + system: "{{ jenkins_user_is_system }}" + create_home: "{{ jenkins_user_create_home }}" + register: jenkins_user_info + +- name: Ensure jenkins home '{{ jenkins_home_path }}' is {{ jenkins_state }} + ansible.builtin.file: + path: "{{ jenkins_home_path }}" + state: "{{ (jenkins_state == 'present') | ternary('directory', 'absent') }}" + mode: "{{ jenkins_home_path_mode | default('0750', true) }}" + owner: "{{ jenkins_user_uid | default(jenkins_user, true) }}" + group: "{{ jenkins_user_gid | default(jenkins_user, true) }}" + notify: + - jenkins_restart + +- name: Ensure jenkins is deployed using {{ jenkins_deployment_method }} + ansible.builtin.include_tasks: + file: "deploy-{{ jenkins_deployment_method }}.yml" diff --git a/roles/jenkins/templates/docker-passwd.j2 b/roles/jenkins/templates/docker-passwd.j2 new file mode 100644 index 0000000..f293507 --- /dev/null +++ b/roles/jenkins/templates/docker-passwd.j2 @@ -0,0 +1,19 @@ +root:x:0:0:root:/root:/bin/bash +daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin +bin:x:2:2:bin:/bin:/usr/sbin/nologin +sys:x:3:3:sys:/dev:/usr/sbin/nologin +sync:x:4:65534:sync:/bin:/bin/sync +games:x:5:60:games:/usr/games:/usr/sbin/nologin +man:x:6:12:man:/var/cache/man:/usr/sbin/nologin +lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin +mail:x:8:8:mail:/var/mail:/usr/sbin/nologin +news:x:9:9:news:/var/spool/news:/usr/sbin/nologin +uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin +proxy:x:13:13:proxy:/bin:/usr/sbin/nologin +www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin +backup:x:34:34:backup:/var/backups:/usr/sbin/nologin +list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin +irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin +_apt:x:42:65534::/nonexistent:/usr/sbin/nologin +nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin +jenkins:x:{{ jenkins_user_uid }}:{{ jenkins_user_gid }}::/var/jenkins_home:/bin/bash diff --git a/roles/jenkins/vars/main.yml b/roles/jenkins/vars/main.yml new file mode 100644 index 0000000..6cfe507 --- /dev/null +++ b/roles/jenkins/vars/main.yml @@ -0,0 +1,8 @@ +--- +jenkins_states: + - absent + - present +jenkins_deployment_methods: + - docker +jenkins_version_channels: >-2 + {{ (jenkins_versions.keys()) | list }}