diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000000..d345b073a78 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,36 @@ +name: molecule test + +on: + push: + branches: + - master + - develop + schedule: + - cron: '0 6 * * 0' + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + - name: molecule + uses: robertdebock/molecule-action@2.0.0 + with: + entrypoint: /usr/local/bin/molecule + args: lint + test: + needs: + - lint + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - name: checkout + uses: actions/checkout@v2 + with: + path: "${{ github.repository }}" + - name: molecule + uses: robertdebock/molecule-action@2.0.0 + env: + PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} diff --git a/.gitignore b/.gitignore index f4a79ecc243..4af4986222e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -molecule/default \ No newline at end of file +actions-runner-linux-* \ No newline at end of file diff --git a/README.md b/README.md index 4c1d9a704fb..8a86f93b4ae 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,24 @@ GitHub Actions Runner ========= - - + + + + -This role will deploy local GitHub Actions Runner. +This role will deploy or redeploy or uninstall and register or unregister local GitHub Actions Runner (version you specified). -**Note:** -The role is in early development stage. -Role is able to: -- install and cofigure local runner -- request reistration token -- register the runner to GitHub - -Currently is missing: -- idempotency -- runner unregistration -- automated testing Requirements ------------ -System must have access to the packages repository (Internet, Red Hat Satellite, etc.). +System must have access to the GitHub. CentOS/Fedora systems require EPEL repository. -`PERSONAL_ACCESS_TOKEN` variable needs to be exported to your environment. +`PERSONAL_ACCESS_TOKEN` variable needs to be exported to your environment. The token has to have admin rights for the repo. +Personal Access Token for your GitHub account can be created [here](https://github.com/settings/tokens). Role Variables -------------- @@ -35,11 +27,17 @@ This is a copy from `defaults/main.yml` ```yaml # Directory where the local runner will be installed -runner_dir: "/opt/actions-runner" +runner_dir: /opt/actions-runner # Version of the GitHub Actions Runner runner_version: "2.165.2" +# If found, replace already registered runner +replace_runner: yes + +# Do not show Ansible logs which may contain sensitive data (registration token) +hide_sensitive_logs: yes + # Personal Access Token for your GitHub account access_token: "{{ lookup('env', 'PERSONAL_ACCESS_TOKEN') }}" @@ -53,24 +51,47 @@ github_server: "https://github.com" # github_repo: "yourrepo" ``` + Example Playbook ---------------- -Simple example. +In this example the role will deploy (or redeploy) the GitHub Actions runner service (default version ins ) and register the runner for the GitHub repo. + +```yaml +--- +- name: GitHub Actions Runner + hosts: all + become: yes + vars: + - runner_version: "2.165.2" + - runner_user: runner + - github_account: myuser + - github_repo: my_awesome_repo + roles: + - role: monolithprojects.github_actions_runner +``` +Here the GitHub Actions runners will be uninstalled, service stopped and unregistered from the GitHub. ```yaml --- -- name: Converge +- name: GitHub Actions Runner hosts: all become: yes + tags: + - uninstall vars: + - runner_version: "2.165.2" - runner_user: runner - - github_account: example - - github_repo: example + - github_account: myuser + - github_repo: my_awesome_repo roles: - - role: monolithprojects/github_actions_runner + - role: monolithprojects.github_actions_runner ``` +ToDo +---- +Full Debian/Ubuntu support + License ------- diff --git a/defaults/main.yml b/defaults/main.yml index d2dcc719409..0f372bf61f4 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,10 +1,16 @@ --- # Directory where the local runner will be installed -runner_dir: "/opt/actions-runner" +runner_dir: /opt/actions-runner # Version of the GitHub Actions Runner runner_version: "2.165.2" +# If found, replace already registered runner +replace_runner: yes + +# Do not show Ansible logs which may contain sensitive data (registration token) +hide_sensitive_logs: yes + # Personal Access Token for your GitHub account access_token: "{{ lookup('env', 'PERSONAL_ACCESS_TOKEN') }}" diff --git a/meta/main.yml b/meta/main.yml index 31392215894..43c6d0d7a7b 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -14,14 +14,14 @@ - name: Fedora versions: - all - - name: Debian - versions: - - jessie - - stretch - - name: Ubuntu - versions: - - xenial - - bionic + # - name: Debian + # versions: + # - jessie + # - stretch + # - name: Ubuntu + # versions: + # - xenial + # - bionic galaxy_tags: - github - actions @@ -30,4 +30,4 @@ - runner - cicd dependencies: - - role: robertdebock.epel \ No newline at end of file + - robertdebock.epel \ No newline at end of file diff --git a/molecule/default/Dockerfile.j2 b/molecule/default/Dockerfile.j2 new file mode 100644 index 00000000000..dfdc410157e --- /dev/null +++ b/molecule/default/Dockerfile.j2 @@ -0,0 +1,31 @@ +# Molecule managed + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +{% if item.env is defined %} +{% for var, value in item.env.items() %} +{% if value %} +ENV {{ var }} {{ value }} +{% endif %} +{% endfor %} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates iproute2 && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash iproute && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash iproute && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml iproute2 && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates iproute2 && xbps-remove -O; fi + +ENV ANSIBLE_USER=ansible SUDO_GROUP=wheel DEPLOY_GROUP=deployer +RUN set -xe \ + && groupadd -r ${ANSIBLE_USER} \ + && groupadd -r ${DEPLOY_GROUP} \ + && useradd -m -g ${ANSIBLE_USER} ${ANSIBLE_USER} \ + && usermod -aG ${SUDO_GROUP} ${ANSIBLE_USER} \ + && usermod -aG ${DEPLOY_GROUP} ${ANSIBLE_USER} \ + && sed -i "/^%${SUDO_GROUP}/s/ALL\$/NOPASSWD:ALL/g" /etc/sudoers \ No newline at end of file diff --git a/molecule/default/INSTALL.rst b/molecule/default/INSTALL.rst new file mode 100644 index 00000000000..6a44bde9efa --- /dev/null +++ b/molecule/default/INSTALL.rst @@ -0,0 +1,22 @@ +******* +Docker driver installation guide +******* + +Requirements +============ + +* Docker Engine + +Install +======= + +Please refer to the `Virtual environment`_ documentation for installation best +practices. If not using a virtual environment, please consider passing the +widely recommended `'--user' flag`_ when invoking ``pip``. + +.. _Virtual environment: https://virtualenv.pypa.io/en/latest/ +.. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site + +.. code-block:: bash + + $ pip install 'molecule[docker]' diff --git a/molecule/default/actions-runner-linux.tar.gz.REMOVED.git-id b/molecule/default/actions-runner-linux.tar.gz.REMOVED.git-id new file mode 100644 index 00000000000..e621040e1ed --- /dev/null +++ b/molecule/default/actions-runner-linux.tar.gz.REMOVED.git-id @@ -0,0 +1 @@ +505e69bab8d510528aa662ef554436d57c936f38 \ No newline at end of file diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml new file mode 100644 index 00000000000..26b194d69f6 --- /dev/null +++ b/molecule/default/converge.yml @@ -0,0 +1,24 @@ +--- +- name: Converge + user: ansible + hosts: all + become: yes + vars: + - runner_user: ansible + - github_repo: ansible-github_actions_runner-testrepo + - github_account: monolithprojects + roles: + - role: ansible-github_actions_runner + +- name: Uninstall + user: ansible + hosts: all + become: yes + tags: + - uninstall + vars: + - runner_user: ansible + - github_repo: ansible-github_actions_runner-testrepo + - github_account: monolithprojects + roles: + - role: ansible-github_actions_runner \ No newline at end of file diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml new file mode 100644 index 00000000000..90c4688e16b --- /dev/null +++ b/molecule/default/molecule.yml @@ -0,0 +1,75 @@ +--- +driver: + name: docker +lint: | + yamllint . +platforms: + - name: CentOS7 + image: monolithprojects/systemd-centos7:latest + command: /sbin/init + tmpfs: + - /run + - /tmp + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: no + pre_build_image: yes + - name: CentOS8 + image: monolithprojects/systemd-centos8:latest + command: /sbin/init + tmpfs: + - /run + - /tmp + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: no + pre_build_image: yes + # - name: Ubuntu16 + # image: monolithprojects/systemd-ubuntu16:latest + # command: /sbin/init + # tmpfs: + # - /run + # - /tmp + # volumes: + # - /sys/fs/cgroup:/sys/fs/cgroup:ro + # privileged: no + # pre_build_image: yes + # - name: Ubuntu18 + # image: monolithprojects/systemd-ubuntu18:latest + # command: /sbin/init + # tmpfs: + # - /run + # - /tmp + # volumes: + # - /sys/fs/cgroup:/sys/fs/cgroup:ro + # privileged: no + # pre_build_image: yes +provisioner: + name: ansible + log: false + # env: + # PERSONAL_ACCESS_TOKEN: $PERSONAL_ACCESS_TOKEN + inventory: + host_vars: + CentOS8: + ansible_python_interpreter: /usr/bin/python3 +verifier: + name: ansible +dependency: + name: galaxy + options: + ignore-certs: True + ignore-errors: True +scenario: + name: default + test_sequence: + - dependency + - lint + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - cleanup + - destroy \ No newline at end of file diff --git a/molecule/default/requirements.yml b/molecule/default/requirements.yml new file mode 100644 index 00000000000..f3b33d4a590 --- /dev/null +++ b/molecule/default/requirements.yml @@ -0,0 +1,3 @@ +--- +- role: robertdebock.epel + version: master \ No newline at end of file diff --git a/molecule/default/tests/__pycache__/test_default.cpython-37.pyc b/molecule/default/tests/__pycache__/test_default.cpython-37.pyc new file mode 100644 index 00000000000..5cd7b75f32a Binary files /dev/null and b/molecule/default/tests/__pycache__/test_default.cpython-37.pyc differ diff --git a/molecule/default/tests/test_default.py b/molecule/default/tests/test_default.py new file mode 100644 index 00000000000..9e0e1890dbd --- /dev/null +++ b/molecule/default/tests/test_default.py @@ -0,0 +1,15 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE'] +).get_hosts('all') + + +def test_hosts_file(host): + f = host.file('/etc/hosts') + + assert f.exists + assert f.user == 'root' + assert f.group == 'root' diff --git a/tasks/collect_info.yml b/tasks/collect_info.yml new file mode 100644 index 00000000000..89475ecc311 --- /dev/null +++ b/tasks/collect_info.yml @@ -0,0 +1,48 @@ +--- +- name: Get registration token (RUN ONCE) + uri: + url: "https://api.github.com/repos/{{ github_account }}/{{ github_repo }}/actions/runners/registration-token" + user: "{{ github_account }}" + password: "{{ access_token }}" + method: POST + status_code: 201 + force_basic_auth: yes + register: registration + run_once: yes + tags: + - install + - uninstall + +- name: Check currently registered runners (RUN ONCE) + uri: + url: "https://api.github.com/repos/{{ github_account }}/{{ github_repo }}/actions/runners" + user: "{{ github_account }}" + password: "{{ access_token }}" + method: GET + status_code: 200 + force_basic_auth: yes + register: registered_runners + run_once: yes + tags: + - install + - uninstall + +- name: Check service facts + service_facts: + tags: + - install + - uninstall + +- name: Combine Github account and repo names + set_fact: + svc_name: "{{ github_account }}-{{ github_repo }}" + tags: + - install + - uninstall + +- name: Build service name + set_fact: + runner_service: "actions.runner.{{ svc_name[:45] }}.{{ ansible_hostname }}.service" + tags: + - install + - uninstall \ No newline at end of file diff --git a/tasks/install_runner.yml b/tasks/install_runner.yml index 38fb05442f2..72ead07915c 100644 --- a/tasks/install_runner.yml +++ b/tasks/install_runner.yml @@ -10,65 +10,57 @@ tags: - install -- name: Download runner package - local_action: - module: get_url +- name: Download runner package version - "{{ runner_version }}" + get_url: url: "https://github.com/actions/runner/releases/download/v{{ runner_version }}/actions-runner-linux-x64-{{ runner_version }}.tar.gz" - dest: ./actions-runner-linux.tar.gz + dest: "./actions-runner-linux-{{ runner_version }}.tar.gz" + force: no run_once: yes + delegate_to: localhost + when: runner_version != "latest" tags: - install - name: Unarchive package unarchive: - src: ./actions-runner-linux.tar.gz + src: "./actions-runner-linux-{{ runner_version }}.tar.gz" dest: "{{ runner_dir }}/" owner: "{{ runner_user }}" tags: - install -- name: Get registration token - uri: - url: "https://api.github.com/repos/{{ github_account }}/{{ github_repo }}/actions/runners/registration-token" - user: "{{ github_account }}" - password: "{{ access_token }}" - method: POST - status_code: 201 - force_basic_auth: yes - register: registration - run_once: yes +- name: Register runner + command: "{{ runner_dir }}/./config.sh --url {{ github_server }}/{{ github_account }}/{{ github_repo }} --token {{ registration.json.token }} --unattended" + args: + chdir: "{{ runner_dir }}" + # became: yes + become_user: "{{ runner_user }}" + no_log: "{{ hide_sensitive_logs }}" + when: ansible_hostname not in registered_runners.json.runners|map(attribute='name')|list tags: - install - - uninstall -# - name: Sstop and disable Github Actions Runner service if it is running -# systemd: -# name: "actions.runner.{{ github_account }}-{{ github_repo }}.{{ ansible_hostname }}" -# state: stopped -# enabled: no -# tags: -# - uninstall - -# - name: Unregister runner -# command: "{{ runner_dir }}/./config.sh remove --token {{ registration.json.token }} --unattended" -# become_user: "{{ runner_user }}" -# tags: -# - uninstall - -- name: Register runner - command: "{{ runner_dir }}/config.sh --url {{ github_server }}/{{ github_account }}/{{ github_repo }} --token {{ registration.json.token }} --unattended" +- name: Replace registered runner + command: "{{ runner_dir }}/config.sh --url {{ github_server }}/{{ github_account }}/{{ github_repo }} --token {{ registration.json.token }} --unattended --replace" + args: + chdir: "{{ runner_dir }}" + # became: yes become_user: "{{ runner_user }}" + no_log: "{{ hide_sensitive_logs }}" + when: replace_runner and ansible_hostname in registered_runners.json.runners|map(attribute='name')|list tags: - install - name: Install service - shell: "cd {{ runner_dir }} && ./svc.sh install" + command: "./svc.sh install" + args: + chdir: "{{ runner_dir }}" tags: - install - name: Start and enable Github Actions Runner service systemd: - name: "actions.runner.{{ github_account }}-{{ github_repo }}.{{ ansible_hostname }}" + name: "{{ runner_service }}" state: started enabled: yes tags: diff --git a/tasks/main.yml b/tasks/main.yml index 10c610f02c4..c26f604f70b 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,3 +1,17 @@ --- +- include_tasks: collect_info.yml + tags: + - install + - uninstall + - include_tasks: install_deps.yml -- include_tasks: install_runner.yml \ No newline at end of file + tags: + - install + +- include_tasks: uninstall_runner.yml + tags: + - uninstall + +- include_tasks: install_runner.yml + tags: + - install \ No newline at end of file diff --git a/tasks/uninstall_runner.yml b/tasks/uninstall_runner.yml new file mode 100644 index 00000000000..191d19aba37 --- /dev/null +++ b/tasks/uninstall_runner.yml @@ -0,0 +1,42 @@ +--- +- name: Stop and disable GitHub Actions Runner service + systemd: + name: "{{ runner_service }}" + state: stopped + enabled: no + when: runner_service in services + tags: + - uninstall + +- name: Remove GitHub Actions Runner service + file: + path: "{{ item }}" + state: absent + with_items: + - "/etc/systemd/system/{{ runner_service }}" + - "{{ runner_dir }}/.service" + tags: + - uninstall + +- name: Reload systemd + systemd: + daemon_reload: yes + tags: + - uninstall + +- name: Check GitHub Actions runner file + stat: + path: "{{ runner_dir }}/.runner" + register: runner_file + tags: + - uninstall + +- name: Unregister runner from the GitHub + command: "./config.sh remove --token {{ registration.json.token }} --unattended" + args: + chdir: "{{ runner_dir }}" + become_user: "{{ runner_user }}" + no_log: "{{ hide_sensitive_logs }}" + when: ansible_hostname in registered_runners.json.runners|map(attribute='name')|list and runner_file.stat.exists + tags: + - uninstall \ No newline at end of file