Skip to content

Commit 637d682

Browse files
feat: initial windows support
1 parent 68d961c commit 637d682

10 files changed

+248
-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

+5-5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
status_code: 201
2828
force_basic_auth: true
2929
register: registration
30+
delegate_to: localhost
3031
run_once: true
3132

3233
- name: "Check currently registered runners for repo {{ '(RUN ONCE)' if all_runners_in_same_repo else '' }}"
@@ -42,21 +43,20 @@
4243
status_code: 200
4344
force_basic_auth: true
4445
register: registered_runners
46+
delegate_to: localhost
4547
run_once: "{{ all_runners_in_same_repo }}"
4648

4749
- name: Get Runner User IDs
4850
ansible.builtin.command: id -u "{{ runner_user }}"
4951
changed_when: false
5052
register: runner_user_id
53+
when: github_actions_system != "win"
5154

5255
- name: Get Runner Group IDs
5356
ansible.builtin.command: id -g "{{ runner_user }}"
5457
changed_when: false
5558
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' }}"
59+
when: github_actions_system != "win"
6060

6161
- name: Find the latest runner version (RUN ONCE)
6262
ansible.builtin.uri:
@@ -77,4 +77,4 @@
7777
- name: Get systemd service facts
7878
ansible.builtin.service_facts:
7979
register: service_facts
80-
when: ansible_facts.system == "Linux"
80+
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

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