diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fac1c60 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## 1.0.0 + +* Initial Release \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..eeceb35 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Ansible Collection - enbewe.woodpecker + +Collecion to deploy woodpecker build server. + +## Playbooks + +### enbewe.woodpecker.deployment +Deploys the role `enbewe.woodpecker.woodpecker` to all hosts of the group `woodpecker`. + +## Roles +Installs the [Woodpecker CI](https://woodpecker-ci.org/) server as well as a runner as docker containers on the machine. + +The software is deployed as containers in podman. diff --git a/galaxy.yml b/galaxy.yml new file mode 100644 index 0000000..a703fba --- /dev/null +++ b/galaxy.yml @@ -0,0 +1,67 @@ +--- +### REQUIRED +# The namespace of the collection. This can be a company/brand/organization or product namespace under which all +# content lives. May only contain alphanumeric lowercase characters and underscores. Namespaces cannot start with +# underscores or numbers and cannot contain consecutive underscores +namespace: 'enbewe' + +# The name of the collection. Has the same character restrictions as 'namespace' +name: 'woodpecker' + +# The version of the collection. Must be compatible with semantic versioning +version: '1.0.0' + +# The path to the Markdown (.md) readme file. This path is relative to the root of the collection +readme: 'README.md' + +# A list of the collection's content authors. Can be just the name or in the format 'Full Name (url) +# @nicks:irc/im.site#channel' +authors: + - 'Nis Wechselberg ' + + +### OPTIONAL but strongly recommended +# A short summary description of the collection +description: 'Deployment tools for woodpecker build server' + +# Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only +# accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file' +license: + - 'MIT' + +# A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character +# requirements as 'namespace' and 'name' +tags: + - 'linux' + +# Collections that this collection requires to be installed for it to be usable. The key of the dict is the +# collection label 'namespace.name'. The value is a version range +# L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification). Multiple version +# range specifiers can be set and are separated by ',' +dependencies: + containers.podman: '1.13.0' + +# The URL of the originating SCM repository +repository: 'https://git.enbewe.de/Coding/ansible-collection-woodpecker' + +# The URL to any online docs +# documentation: http://docs.example.com + +# The URL to the homepage of the collection/project +# homepage: http://example.com + +# The URL to the collection issue tracker +# issues: http://example.com/issue/tracker + +# A list of file glob-like patterns used to filter any files or directories that should not be included in the build +# artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This +# uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry', +# and '.git' are always filtered. Mutually exclusive with 'manifest' +# build_ignore: [] + +# A dict controlling use of manifest directives used in building the collection artifact. The key 'directives' is a +# list of MANIFEST.in style +# L(directives,https://packaging.python.org/en/latest/guides/using-manifest-in/#manifest-in-commands). The key +# 'omit_default_directives' is a boolean that controls whether the default directives are used. Mutually exclusive +# with 'build_ignore' +# manifest: null diff --git a/meta/runtime.yml b/meta/runtime.yml new file mode 100644 index 0000000..d6c6f44 --- /dev/null +++ b/meta/runtime.yml @@ -0,0 +1,52 @@ +--- +# Collections must specify a minimum required ansible version to upload +# to galaxy +requires_ansible: '>=2.17.0' + +# Content that Ansible needs to load from another location or that has +# been deprecated/removed +# plugin_routing: +# action: +# redirected_plugin_name: +# redirect: ns.col.new_location +# deprecated_plugin_name: +# deprecation: +# removal_version: "4.0.0" +# warning_text: | +# See the porting guide on how to update your playbook to +# use ns.col.another_plugin instead. +# removed_plugin_name: +# tombstone: +# removal_version: "2.0.0" +# warning_text: | +# See the porting guide on how to update your playbook to +# use ns.col.another_plugin instead. +# become: +# cache: +# callback: +# cliconf: +# connection: +# doc_fragments: +# filter: +# httpapi: +# inventory: +# lookup: +# module_utils: +# modules: +# netconf: +# shell: +# strategy: +# terminal: +# test: +# vars: + +# Python import statements that Ansible needs to load from another location +# import_redirection: +# ansible_collections.ns.col.plugins.module_utils.old_location: +# redirect: ansible_collections.ns.col.plugins.module_utils.new_location + +# Groups of actions/modules that take a common set of options +# action_groups: +# group_name: +# - module1 +# - module2 diff --git a/playbooks/deployment.yml b/playbooks/deployment.yml new file mode 100644 index 0000000..d3ef5c9 --- /dev/null +++ b/playbooks/deployment.yml @@ -0,0 +1,5 @@ +--- +- name: 'Deploy collection roles to matching host groups' + hosts: 'woodpecker' + roles: + - 'enbewe.woodpecker.woodpecker' diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 0000000..269a4c2 --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,31 @@ +# Collections Plugins Directory + +This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that +is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that +would contain module utils and modules respectively. + +Here is an example directory of the majority of plugins currently supported by Ansible: + +``` +└── plugins + ├── action + ├── become + ├── cache + ├── callback + ├── cliconf + ├── connection + ├── filter + ├── httpapi + ├── inventory + ├── lookup + ├── module_utils + ├── modules + ├── netconf + ├── shell + ├── strategy + ├── terminal + ├── test + └── vars +``` + +A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible-core/2.17/plugins/plugins.html). diff --git a/roles/woodpecker/defaults/main.yml b/roles/woodpecker/defaults/main.yml new file mode 100644 index 0000000..e7c96a4 --- /dev/null +++ b/roles/woodpecker/defaults/main.yml @@ -0,0 +1,9 @@ +--- +woodpecker_podman_network: 'woodpecker' + +woodpecker_server_image_name: 'docker.io/woodpeckerci/woodpecker-server' +woodpecker_server_image_tag: 'latest-alpine' +woodpecker_agent_image_name: 'docker.io/woodpeckerci/woodpecker-agent' +woodpecker_agent_image_tag: 'latest-alpine' + +woodpecker_server_container_name: 'woodpecker-server' diff --git a/roles/woodpecker/handlers/main.yml b/roles/woodpecker/handlers/main.yml new file mode 100644 index 0000000..6b9505d --- /dev/null +++ b/roles/woodpecker/handlers/main.yml @@ -0,0 +1,14 @@ +--- +- name: 'Restart woodpecker-server container' + become: true + ansible.builtin.service: + name: 'container-woodpecker-server' + state: 'restarted' + daemon_reload: true + +- name: 'Restart woodpecker-agent container' + become: true + ansible.builtin.service: + name: 'container-woodpecker-agent' + state: 'restarted' + daemon_reload: true diff --git a/roles/woodpecker/tasks/main.yml b/roles/woodpecker/tasks/main.yml new file mode 100644 index 0000000..9953f9b --- /dev/null +++ b/roles/woodpecker/tasks/main.yml @@ -0,0 +1,42 @@ +--- +- name: 'Install required software' + become: true + ansible.builtin.apt: + name: 'podman' + state: 'present' + update_cache: true + cache_valid_time: 3600 + +- name: 'Prepare network' + become: true + containers.podman.podman_network: + name: '{{ woodpecker_podman_network }}' + state: 'present' + +- name: 'Copy required files' + become: true + ansible.builtin.template: + src: '{{ item.src }}' + dest: '{{ item.dest }}' + owner: 'root' + group: 'root' + mode: 'u=rw,g=r,o=r' + notify: '{{ item.notify }}' + loop: + - src: 'systemd/container-woodpecker-server.service.j2' + dest: '/etc/systemd/system/container-woodpecker-server.service' + notify: 'Restart woodpecker-server container' + - src: 'systemd/container-woodpecker-agent.service.j2' + dest: '/etc/systemd/system/container-woodpecker-agent.service' + notify: 'Restart woodpecker-agent container' + +- name: 'Start and enable services' + become: true + ansible.builtin.systemd: + name: '{{ item }}' + state: 'started' + daemon_reload: true + enabled: true + loop: + - 'container-woodpecker-server.service' + - 'container-woodpecker-agent.service' diff --git a/roles/woodpecker/templates/systemd/container-woodpecker-agent.service.j2 b/roles/woodpecker/templates/systemd/container-woodpecker-agent.service.j2 new file mode 100644 index 0000000..9adff86 --- /dev/null +++ b/roles/woodpecker/templates/systemd/container-woodpecker-agent.service.j2 @@ -0,0 +1,44 @@ +[Unit] +Description=Podman container-woodpecker-agent.service +Documentation=man:podman-generate-systemd(1) +Wants=network-online.target +After=network-online.target +RequiresMountsFor=%t/containers + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=on-failure +TimeoutStopSec=70 +Type=notify +NotifyAccess=all + +ExecStartPre=/bin/rm -f %t/%n.ctr-id + +ExecStart=/usr/bin/podman run \ + --cidfile=%t/%n.ctr-id \ + --cgroups=no-conmon \ + --rm \ + --sdnotify=conmon \ + --replace \ + --network={{ woodpecker_podman_network }} \ + --detach \ + --tty \ + --volume {{ woodpecker_agent_config_volume }}:/etc/woodpecker:Z \ + --volume /var/run/podman/podman.sock:/var/run/docker.sock:Z \ +{% for environment in woodpecker_agent_environments %} + --env {{ environment.key }}={{ environment.value }} \ +{% endfor %} + --name=woodpecker-agent \ + {{ woodpecker_agent_image_name }}:{{ woodpecker_agent_image_tag }} + +ExecStop=/usr/bin/podman stop \ + --ignore \ + --cidfile=%t/%n.ctr-id + +ExecStopPost=/usr/bin/podman rm \ + --force \ + --ignore \ + --cidfile=%t/%n.ctr-id + +[Install] +WantedBy=default.target diff --git a/roles/woodpecker/templates/systemd/container-woodpecker-server.service.j2 b/roles/woodpecker/templates/systemd/container-woodpecker-server.service.j2 new file mode 100644 index 0000000..4ac4626 --- /dev/null +++ b/roles/woodpecker/templates/systemd/container-woodpecker-server.service.j2 @@ -0,0 +1,44 @@ +[Unit] +Description=Podman container-woodpecker-server.service +Documentation=man:podman-generate-systemd(1) +Wants=network-online.target +After=network-online.target +RequiresMountsFor=%t/containers + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=on-failure +TimeoutStopSec=70 +Type=notify +NotifyAccess=all + +ExecStartPre=/bin/rm -f %t/%n.ctr-id + +ExecStart=/usr/bin/podman run \ + --cidfile=%t/%n.ctr-id \ + --cgroups=no-conmon \ + --rm \ + --sdnotify=conmon \ + --replace \ + --network={{ woodpecker_podman_network }} \ + --detach \ + --tty \ + --publish {{ woodpecker_server_listen_port }}:8000 \ + --volume {{ woodpecker_server_data_volume }}:/var/lib/woodpecker:Z \ +{% for environment in woodpecker_server_environments %} + --env {{ environment.key }}={{ environment.value }} \ +{% endfor %} + --name={{ woodpecker_server_container_name }} \ + {{ woodpecker_server_image_name }}:{{ woodpecker_server_image_tag }} + +ExecStop=/usr/bin/podman stop \ + --ignore \ + --cidfile=%t/%n.ctr-id + +ExecStopPost=/usr/bin/podman rm \ + --force \ + --ignore \ + --cidfile=%t/%n.ctr-id + +[Install] +WantedBy=default.target