Skip to content

Commit 5e08b29

Browse files
Merge pull request #219 from steinwurf/feat/win-support
feat: initial windows support
2 parents 75ae9e5 + 5adc706 commit 5e08b29

10 files changed

+249
-16
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ all_runners_in_same_repo: true
132132
# GitHub Enterprise name
133133
# github_enterprise: "yourenterprise"
134134

135+
# Runner user Windows password - the logon password for the service user when running on windows.
136+
# runner_user_win_password: "{{ lookup('env', 'PASS') }}"
137+
135138
# Configuring a custom .env file
136139
# custom_env: |
137140
# http_proxy=YOUR_URL_HERE

defaults/main.yml

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
runner_user: "{{ lookup('env', 'USER') }}"
44

55
# Directory where the local runner will be installed
6-
runner_dir: /opt/actions-runner
6+
runner_dir: "{{ 'C:\\actions-runner' if ansible_facts.system == 'Win32NT' else '/opt/actions-runner' }}"
77

88
# Version of the GitHub Actions Runner
99
runner_version: "latest"
@@ -42,7 +42,7 @@ runner_group: ""
4242
runner_download_repository: "actions/runner"
4343

4444
# Extra arguments to pass to `config.sh`.
45-
# Several arguments muste be set as one string (i.e. "--ephemeral --my_special_fork")
45+
# Several arguments must be set as one string (i.e. "--ephemeral --my_special_fork")
4646
runner_extra_config_args: ""
4747

4848
# Name to assign to this runner in GitHub (System hostname as default)
@@ -63,6 +63,9 @@ all_runners_in_same_repo: true
6363
# GitHub Enterprise name
6464
# github_enterprise: "yourenterprise"
6565

66+
# Runner user Windows password - the logon password for the service user when running on windows.
67+
# runner_user_win_password: "{{ lookup('env', 'PASS') }}"
68+
6669
# Configuring a custom .env file
6770
# custom_env: |
6871
# http_proxy=YOUR_URL_HERE

tasks/assert.yml

+8
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,11 @@
3131
fail_msg: "github_repo was not found or is using an invalid format."
3232
run_once: true
3333
when: not runner_org and github_enterprise is not defined
34+
35+
- name: Check runner_user_win_password (RUN ONCE)
36+
ansible.builtin.assert:
37+
that:
38+
- runner_user_win_password is defined
39+
fail_msg: "runner_user_win_password was not defined, but it is required on a windows system"
40+
run_once: true
41+
when: github_actions_system == "win"

tasks/collect_info.yml

+7-5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
status_code: 201
2828
force_basic_auth: true
2929
register: registration
30+
delegate_to: localhost
31+
become: false
3032
run_once: true
3133

3234
- name: "Check currently registered runners for repo {{ '(RUN ONCE)' if all_runners_in_same_repo else '' }}"
@@ -42,21 +44,21 @@
4244
status_code: 200
4345
force_basic_auth: true
4446
register: registered_runners
47+
delegate_to: localhost
48+
become: false
4549
run_once: "{{ all_runners_in_same_repo }}"
4650

4751
- name: Get Runner User IDs
4852
ansible.builtin.command: id -u "{{ runner_user }}"
4953
changed_when: false
5054
register: runner_user_id
55+
when: github_actions_system != "win"
5156

5257
- name: Get Runner Group IDs
5358
ansible.builtin.command: id -g "{{ runner_user }}"
5459
changed_when: false
5560
register: runner_user_group_id
56-
57-
- name: Set runner_system variable
58-
ansible.builtin.set_fact:
59-
runner_system: "{{ 'osx' if ansible_facts.system == 'Darwin' else 'linux' }}"
61+
when: github_actions_system != "win"
6062

6163
- name: Find the latest runner version (RUN ONCE)
6264
ansible.builtin.uri:
@@ -77,4 +79,4 @@
7779
- name: Get systemd service facts
7880
ansible.builtin.service_facts:
7981
register: service_facts
80-
when: ansible_facts.system == "Linux"
82+
when: github_actions_system == "linux"

tasks/install_runner.yml renamed to tasks/install_runner_unix.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
- name: Unarchive runner package
2323
ansible.builtin.unarchive:
2424
src: "https://github.com/{{ runner_download_repository }}/releases/download/v{{ runner_version }}/\
25-
actions-runner-{{ runner_system }}-{{ github_actions_architecture }}-{{ runner_version }}.tar.gz"
25+
actions-runner-{{ github_actions_system }}-{{ github_actions_architecture }}-{{ runner_version }}.tar.gz"
2626
dest: "{{ runner_dir }}/"
2727
owner: "{{ runner_user_id.stdout }}"
2828
group: "{{ runner_user_group_id.stdout }}"

tasks/install_runner_win.yml

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
---
2+
- name: Create directory
3+
ansible.windows.win_file:
4+
path: "{{ runner_dir }}"
5+
state: directory
6+
7+
- name: Set owner of directory
8+
ansible.windows.win_owner:
9+
path: "{{ runner_dir }}"
10+
user: "{{ runner_user }}"
11+
12+
- name: Set runner_version variable (If latest)
13+
ansible.builtin.set_fact:
14+
runner_version: "{{ api_response.json.tag_name | regex_replace('^v', '') }}"
15+
when: runner_version == "latest"
16+
17+
- name: Check if desired version already installed
18+
ansible.windows.win_command: "grep -i {{ runner_version }} {{ runner_dir }}\\bin\\Runner.Listener.deps.json"
19+
register: runner_installed
20+
check_mode: false
21+
changed_when: false
22+
ignore_errors: true
23+
24+
- name: Download runner package
25+
ansible.windows.win_get_url:
26+
url: "https://github.com/{{ runner_download_repository }}/releases/download/v{{ runner_version }}/\
27+
actions-runner-{{ github_actions_system }}-{{ github_actions_architecture }}-{{ runner_version }}.zip"
28+
dest: "%TEMP%\\actions-runner-{{ github_actions_system }}-{{ github_actions_architecture }}-{{ runner_version }}.zip"
29+
when: runner_version not in runner_installed.stdout or reinstall_runner
30+
31+
- name: Unarchive runner package
32+
community.windows.win_unzip:
33+
src: "%TEMP%\\actions-runner-{{ github_actions_system }}-{{ github_actions_architecture }}-{{ runner_version }}.zip"
34+
dest: "{{ runner_dir }}\\"
35+
delete_archive: yes
36+
when: runner_version not in runner_installed.stdout or reinstall_runner
37+
38+
- name: Configure custom env file if required
39+
randrej.windows.win_blockinfile:
40+
path: "{{ runner_dir }}\\.env"
41+
block: "{{ custom_env }}"
42+
create: true
43+
marker: "# {mark} ANSIBLE MANAGED BLOCK"
44+
marker_begin: BEGIN
45+
marker_end: END
46+
when: custom_env is defined
47+
48+
- name: Check if runner service name file exist
49+
ansible.windows.win_stat:
50+
path: "{{ runner_dir }}/.service"
51+
register: runner_service_file_path
52+
53+
- name: Set complete GitHub url for repo runner
54+
ansible.builtin.set_fact:
55+
github_full_url: "{{ github_url }}/{{ github_owner | default(github_account) }}/{{ github_repo }}"
56+
when: not runner_org and github_enterprise is not defined
57+
58+
- name: Set complete GitHub url for org runner
59+
ansible.builtin.set_fact:
60+
github_full_url: "{{ github_url }}/{{ github_owner | default(github_account) }}"
61+
when: runner_org | bool and github_enterprise is not defined
62+
63+
- name: Set complete GitHub url for enterprise runner
64+
ansible.builtin.set_fact:
65+
github_full_url: "{{ github_url }}/enterprises/{{ github_enterprise }}"
66+
when: github_enterprise is defined
67+
68+
- name: Register runner # noqa no-changed-when
69+
environment:
70+
RUNNER_ALLOW_RUNASROOT: "1"
71+
ansible.windows.win_command:
72+
"{{ runner_dir }}\\config.cmd \
73+
--url {{ github_full_url }} \
74+
--token {{ registration.json.token }} \
75+
--name {{ runner_name }} \
76+
--labels {{ runner_labels | join(',') }} \
77+
--runnergroup {{ runner_group }} \
78+
--runasservice \
79+
--windowslogonaccount {{ runner_user }} \
80+
--windowslogonpassword {{ runner_user_win_password }} \
81+
--unattended \
82+
{{ runner_extra_config_args }}"
83+
args:
84+
chdir: "{{ runner_dir }}"
85+
changed_when: true
86+
become_method: runas
87+
become_user: "{{ runner_user }}"
88+
become: true
89+
no_log: "{{ hide_sensitive_logs | bool }}"
90+
when: runner_name not in registered_runners.json.runners|map(attribute='name')|list
91+
92+
- name: Replace registered runner # noqa no-changed-when
93+
environment:
94+
RUNNER_ALLOW_RUNASROOT: "1"
95+
ansible.windows.win_command:
96+
"{{ runner_dir }}\\config.cmd \
97+
--url {{ github_full_url }} \
98+
--token {{ registration.json.token }} \
99+
--name {{ runner_name }} \
100+
--labels {{ runner_labels | join(',') }} \
101+
--runasservice \
102+
--windowslogonaccount {{ runner_user }} \
103+
--windowslogonpassword {{ runner_user_win_password }} \
104+
--unattended \
105+
{{ runner_extra_config_args }} \
106+
--replace"
107+
args:
108+
chdir: "{{ runner_dir }}"
109+
changed_when: true
110+
become_method: runas
111+
become_user: "{{ runner_user }}"
112+
become: true
113+
no_log: "{{ hide_sensitive_logs | bool }}"
114+
when: >
115+
runner_name in registered_runners.json.runners|map(attribute='name')|list and
116+
reinstall_runner
117+
118+
- name: Read service name from file
119+
ansible.windows.win_command: "cat {{ runner_dir }}\\.service"
120+
register: runner_service
121+
changed_when: false
122+
123+
- name: START and enable Github Actions Runner service
124+
ansible.windows.win_service:
125+
name: "{{ runner_service.stdout }}"
126+
start_mode: auto
127+
state: started
128+
when: runner_state|lower == "started"
129+
130+
- name: STOP and disable Github Actions Runner service
131+
ansible.windows.win_service:
132+
name: "{{ runner_service.stdout }}"
133+
start_mode: manual
134+
state: stopped
135+
when: runner_state|lower == "stopped"
136+
137+
- name: Version changed - RESTART Github Actions Runner service
138+
ansible.windows.win_service:
139+
name: "{{ runner_service.stdout }}"
140+
start_mode: auto
141+
state: restarted
142+
when: runner_version not in runner_installed.stdout and not runner_state|lower == "stopped"

tasks/main.yml

+30-8
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,48 @@
55
- install
66
- uninstall
77

8-
- name: Include Information collection taks
8+
- name: Include Information collection tasks
99
ansible.builtin.include_tasks: collect_info.yml
1010
tags:
1111
- install
1212
- uninstall
1313

1414
- name: Include tasks to install dependencies
1515
ansible.builtin.include_tasks: install_deps.yml
16-
when: runner_state|lower == "started" or runner_state|lower == "stopped"
16+
when:
17+
- runner_state|lower == "started" or runner_state|lower == "stopped"
18+
- github_actions_system == "linux"
1719
tags:
1820
- install
1921

20-
- name: Include tasks to uninstall runner
21-
ansible.builtin.include_tasks: uninstall_runner.yml
22-
when: reinstall_runner or runner_state|lower == "absent"
22+
- name: Include tasks to uninstall runner (UNIX-like)
23+
ansible.builtin.include_tasks: uninstall_runner_unix.yml
24+
when:
25+
- reinstall_runner or runner_state|lower == "absent"
26+
- github_actions_system == "linux" or github_actions_system == "osx"
2327
tags:
2428
- uninstall
2529

26-
- name: Include tasks to install runner
27-
ansible.builtin.include_tasks: install_runner.yml
28-
when: runner_state|lower == "started" or runner_state|lower == "stopped"
30+
- name: Include tasks to uninstall runner (Windows)
31+
ansible.builtin.include_tasks: uninstall_runner_win.yml
32+
when:
33+
- reinstall_runner or runner_state|lower == "absent"
34+
- github_actions_system == "win"
35+
tags:
36+
- uninstall
37+
38+
- name: Include tasks to install runner (UNIX-like)
39+
ansible.builtin.include_tasks: install_runner_unix.yml
40+
when:
41+
- runner_state|lower == "started" or runner_state|lower == "stopped"
42+
- github_actions_system == "linux" or github_actions_system == "osx"
43+
tags:
44+
- install
45+
46+
- name: Include tasks to install runner (Windows)
47+
ansible.builtin.include_tasks: install_runner_win.yml
48+
when:
49+
- runner_state|lower == "started" or runner_state|lower == "stopped"
50+
- github_actions_system == "win"
2951
tags:
3052
- install
File renamed without changes.

tasks/uninstall_runner_win.yml

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
- name: Check if runner service name file exist
3+
ansible.windows.win_stat:
4+
path: "{{ runner_dir }}/.service"
5+
register: runner_service_file_path
6+
7+
- name: Read service name from file
8+
ansible.windows.win_command: "cat {{ runner_dir }}\\.service"
9+
register: runner_service
10+
changed_when: false
11+
when: runner_service_file_path.stat.exists
12+
13+
- name: Uninstall service runner
14+
ansible.windows.win_shell: |
15+
if(Get-Service {{ runner_service.stdout }} -ErrorAction SilentlyContinue) {
16+
Write-Host "Stopping and removing service: {{ runner_service.stdout }}"
17+
sc.exe stop "{{ runner_service.stdout }}"
18+
sc.exe delete "{{ runner_service.stdout }}"
19+
}
20+
args:
21+
chdir: "{{ runner_dir }}"
22+
register: uninstall_service_runner
23+
changed_when: "'Stopping and removing service:' in uninstall_service_runner.stdout"
24+
when: runner_service_file_path.stat.exists
25+
26+
- name: Check GitHub Actions runner file
27+
ansible.windows.win_stat:
28+
path: "{{ runner_dir }}/.runner"
29+
register: runner_file
30+
31+
- name: Unregister runner from the GitHub
32+
environment:
33+
RUNNER_ALLOW_RUNASROOT: "1"
34+
ansible.windows.win_command: "config.cmd remove --token {{ registration.json.token }} --name {{ runner_name }} --unattended"
35+
args:
36+
chdir: "{{ runner_dir }}"
37+
become: true
38+
become_method: runas
39+
become_user: "{{ runner_user }}"
40+
no_log: "{{ hide_sensitive_logs | bool }}"
41+
changed_when: true
42+
when: runner_name in registered_runners.json.runners|map(attribute='name')|list and runner_file.stat.exists
43+
44+
- name: Delete runner directory
45+
ansible.windows.win_file:
46+
path: "{{ runner_dir }}"
47+
state: absent

vars/main.yml

+6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
github_actions_architecture_map:
44
amd64: x64
55
x86_64: x64
6+
64-bit: x64
67
armv7l: arm
78
aarch64: arm64
89
arm64: arm64
910
github_actions_architecture: "{{ github_actions_architecture_map[ansible_facts.architecture] }}"
11+
github_actions_system_map:
12+
Darwin: osx
13+
Linux: linux
14+
Win32NT: win
15+
github_actions_system: "{{ github_actions_system_map[ansible_facts.system] }}"

0 commit comments

Comments
 (0)