Compare commits
	
		
			3 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 2d09ce28e7 | |||
| 8d1cc8e160 | |||
| 4d3faf3617 | 
							
								
								
									
										33
									
								
								.github/workflows/vagrant.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								.github/workflows/vagrant.yml
									
									
									
									
										vendored
									
									
								
							| @@ -3,17 +3,22 @@ name: homelab-ci | |||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     branches: |     branches: | ||||||
|       - github_actions |       - main | ||||||
|       # - main |       - testing | ||||||
|       # - testing |  | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   homelab-ci: |   homelab-ci: | ||||||
|     runs-on: macos-latest |     runs-on: macos-13 | ||||||
|  |  | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v3 | ||||||
|  |  | ||||||
|  |       - name: Setup tmate session | ||||||
|  |         uses: mxschmitt/action-tmate@v3 | ||||||
|  |         with: | ||||||
|  |           detached: true | ||||||
|  |           limit-access-to-actor: true | ||||||
|  |  | ||||||
|       - name: Cache Vagrant boxes |       - name: Cache Vagrant boxes | ||||||
|         uses: actions/cache@v3 |         uses: actions/cache@v3 | ||||||
|         with: |         with: | ||||||
| @@ -22,19 +27,23 @@ jobs: | |||||||
|           restore-keys: | |           restore-keys: | | ||||||
|             ${{ runner.os }}-vagrant- |             ${{ runner.os }}-vagrant- | ||||||
|  |  | ||||||
|  |       - name: Install Tools | ||||||
|  |         run: brew install nmap tree | ||||||
|  |  | ||||||
|  |       - name: Install VirtualBox | ||||||
|  |         run: brew install --cask virtualbox | ||||||
|  |  | ||||||
|  |       - name: Install Vagrant | ||||||
|  |         run: brew install --cask vagrant | ||||||
|  |  | ||||||
|       - name: Install Ansible |       - name: Install Ansible | ||||||
|         run: brew install ansible@7 |         run: brew install ansible | ||||||
|  |  | ||||||
|       - name: Software Versions |       - name: Software Versions | ||||||
|         run: | |         run: | | ||||||
|           printf "VirtualBox " |           printf "VirtualBox "; vboxmanage --version | ||||||
|           vboxmanage --version |  | ||||||
|           vagrant --version |           vagrant --version | ||||||
|           export PATH="/usr/local/opt/ansible@7/bin:$PATH" |  | ||||||
|           ansible --version |           ansible --version | ||||||
|  |  | ||||||
|       - name: Vagrant Up with Dockerbox Playbook |       - name: Vagrant Up with Dockerbox Playbook | ||||||
|         run: | |         run: ./scripts/github-vagrant.sh | ||||||
|           export PATH="/usr/local/opt/ansible@7/bin:$PATH" |  | ||||||
|           PLAYBOOK=dockerbox vagrant up |  | ||||||
|           vagrant ssh -c "docker ps" |  | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,4 @@ | |||||||
| .ansible* |  | ||||||
| /environments/ |  | ||||||
| .playbook | .playbook | ||||||
| .vagrant* | .vagrant* | ||||||
| .vscode | .vscode | ||||||
|  | /environments/ | ||||||
							
								
								
									
										3
									
								
								Vagrantfile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								Vagrantfile
									
									
									
									
										vendored
									
									
								
							| @@ -36,6 +36,7 @@ Vagrant.configure("2") do |config| | |||||||
|   config.vm.provider :virtualbox do |vbox| |   config.vm.provider :virtualbox do |vbox| | ||||||
|     vbox.cpus   = VAGRANT_CPUS |     vbox.cpus   = VAGRANT_CPUS | ||||||
|     vbox.memory = VAGRANT_MEM |     vbox.memory = VAGRANT_MEM | ||||||
|  |     vbox.gui    = true | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   # Provision with Ansible |   # Provision with Ansible | ||||||
| @@ -43,6 +44,6 @@ Vagrant.configure("2") do |config| | |||||||
|     ENV['ANSIBLE_ROLES_PATH'] = File.dirname(__FILE__) + "/roles" |     ENV['ANSIBLE_ROLES_PATH'] = File.dirname(__FILE__) + "/roles" | ||||||
|     ansible.compatibility_mode = "2.0" |     ansible.compatibility_mode = "2.0" | ||||||
|     ansible.playbook = "dev/" + PLAYBOOK + ".yml" |     ansible.playbook = "dev/" + PLAYBOOK + ".yml" | ||||||
|     ansible.raw_arguments = ["--diff"] |     ansible.raw_arguments = ["--diff", "-vvvv"] | ||||||
|   end |   end | ||||||
| end | end | ||||||
|   | |||||||
| @@ -4,12 +4,8 @@ manage_network: false | |||||||
|  |  | ||||||
| # Import my GPG key for git signature verification | # Import my GPG key for git signature verification | ||||||
| root_gpgkeys: | root_gpgkeys: | ||||||
|   - name: kris@lamoureux.io |  | ||||||
|     id: 42A3A92C5DA0F3E5F71A3710105B748C1362EB96 |  | ||||||
|   # Older key, but still in use |  | ||||||
|   - name: kris@lamoureux.io |   - name: kris@lamoureux.io | ||||||
|     id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925 |     id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925 | ||||||
|     server: keyserver.ubuntu.com |  | ||||||
|  |  | ||||||
| # proxy | # proxy | ||||||
| proxy: | proxy: | ||||||
|   | |||||||
| @@ -1,46 +0,0 @@ | |||||||
| ############## |  | ||||||
| #### base #### |  | ||||||
| ############## |  | ||||||
|  |  | ||||||
| allow_reboot: false |  | ||||||
| manage_network: false |  | ||||||
|  |  | ||||||
| users: |  | ||||||
|   kris: |  | ||||||
|     uid: 1001 |  | ||||||
|     gid: 1001 |  | ||||||
|     home: true |  | ||||||
|     ansible_temp: true |  | ||||||
|  |  | ||||||
| ################ |  | ||||||
| #### podman #### |  | ||||||
| ################ |  | ||||||
|  |  | ||||||
| user_namespaces: |  | ||||||
|   - kris |  | ||||||
|  |  | ||||||
| podman_compose_deploy: |  | ||||||
|   kris: |  | ||||||
|     root: /home/kris/podman_root |  | ||||||
|     trusted_keys: |  | ||||||
|       - id: FBF673CEEC030F8AECA814E73EDA9C3441EDA925 |  | ||||||
|         keyserver: keyserver.ubuntu.com |  | ||||||
|     compose: |  | ||||||
|       - name: traefik |  | ||||||
|         url: https://github.com/krislamo/traefik |  | ||||||
|         version: d62bd06b37ecf0993962b0449a9d708373f9e381 |  | ||||||
|         enabled: true |  | ||||||
|         accept_newhostkey: true # Consider verifying manually instead |  | ||||||
|         env: |  | ||||||
|           DASHBOARD: true |  | ||||||
|  |  | ||||||
| ################### |  | ||||||
| #### Bitwarden #### |  | ||||||
| ################### |  | ||||||
|  |  | ||||||
| # Get Installation ID & Key at https://bitwarden.com/host/ |  | ||||||
| bitwarden_domain: vault.local.krislamo.org |  | ||||||
| bitwarden_dbpass: password |  | ||||||
| bitwarden_install_id: 4ea840a3-532e-4cb6-a472-abd900728b23 |  | ||||||
| bitwarden_install_key: 1yB3Z2gRI0KnnH90C6p |  | ||||||
| #bitwarden_prodution: true |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| - name: Install Podman server |  | ||||||
|   hosts: all |  | ||||||
|   become: true |  | ||||||
|   vars_files: |  | ||||||
|     - host_vars/podman.yml |  | ||||||
|   roles: |  | ||||||
|     - base |  | ||||||
|     - podman |  | ||||||
|     - bitwarden |  | ||||||
| @@ -4,5 +4,4 @@ | |||||||
|   roles: |   roles: | ||||||
|     - base |     - base | ||||||
|     - jenkins |     - jenkins | ||||||
|     - proxy |  | ||||||
|     - docker |     - docker | ||||||
|   | |||||||
| @@ -3,9 +3,9 @@ | |||||||
|   become: true |   become: true | ||||||
|   roles: |   roles: | ||||||
|     - base |     - base | ||||||
|     - jenkins |  | ||||||
|     - docker |     - docker | ||||||
|     - mariadb |  | ||||||
|     - traefik |     - traefik | ||||||
|     - nextcloud |     - nextcloud | ||||||
|     - proxy |     - jenkins | ||||||
|  |     - prometheus | ||||||
|  |     - nginx | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ | |||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: smb.conf.j2 |     src: smb.conf.j2 | ||||||
|     dest: /etc/samba/smb.conf |     dest: /etc/samba/smb.conf | ||||||
|     mode: "644" |     mode: "700" | ||||||
|   notify: restart_samba |   notify: restart_samba | ||||||
|  |  | ||||||
| - name: Start smbd and enable on boot | - name: Start smbd and enable on boot | ||||||
|   | |||||||
| @@ -80,30 +80,14 @@ | |||||||
|     state: present |     state: present | ||||||
|     uid: "{{ item.value.uid }}" |     uid: "{{ item.value.uid }}" | ||||||
|     group: "{{ item.value.gid }}" |     group: "{{ item.value.gid }}" | ||||||
|     groups: "{{ item.value.groups | default([]) }}" |  | ||||||
|     shell: "{{ item.value.shell | default('/bin/bash') }}" |     shell: "{{ item.value.shell | default('/bin/bash') }}" | ||||||
|     create_home: "{{ item.value.home | default(false) }}" |     create_home: "{{ item.value.home | default(false) }}" | ||||||
|     home: "{{ item.value.homedir | default('/home/' + item.key) }}" |  | ||||||
|     system: "{{ item.value.system | default(false) }}" |     system: "{{ item.value.system | default(false) }}" | ||||||
|   loop: "{{ users | dict2items }}" |   loop: "{{ users | dict2items }}" | ||||||
|   loop_control: |   loop_control: | ||||||
|     label: "{{ item.key }}" |     label: "{{ item.key }}" | ||||||
|   when: users is defined |   when: users is defined | ||||||
|  |  | ||||||
| - name: Create Ansible's temporary remote directory for users |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ item.value.homedir | default('/home/' + item.key) }}/.ansible/tmp" |  | ||||||
|     state: directory |  | ||||||
|     mode: "700" |  | ||||||
|     owner: "{{ item.key }}" |  | ||||||
|     group: "{{ item.value.gid }}" |  | ||||||
|   loop: "{{ users | dict2items }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.key }}" |  | ||||||
|   when: |  | ||||||
|     - users is defined |  | ||||||
|     - item.value.ansible_temp | default(false) |  | ||||||
|  |  | ||||||
| - name: Set authorized_keys for system users | - name: Set authorized_keys for system users | ||||||
|   ansible.posix.authorized_key: |   ansible.posix.authorized_key: | ||||||
|     user: "{{ item.key }}" |     user: "{{ item.key }}" | ||||||
|   | |||||||
| @@ -18,28 +18,6 @@ | |||||||
|     src: /etc/wireguard/privatekey |     src: /etc/wireguard/privatekey | ||||||
|   register: wgkey |   register: wgkey | ||||||
|  |  | ||||||
| - name: Check if WireGuard preshared key file exists |  | ||||||
|   ansible.builtin.stat: |  | ||||||
|     path: /etc/wireguard/presharedkey-{{ item.name }} |  | ||||||
|   loop: "{{ wireguard.peers }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.name }}" |  | ||||||
|   register: presharedkey_files |  | ||||||
|  |  | ||||||
| - name: Grab WireGuard preshared key for configuration |  | ||||||
|   ansible.builtin.slurp: |  | ||||||
|     src: /etc/wireguard/presharedkey-{{ item.item.name }} |  | ||||||
|   register: wgshared |  | ||||||
|   loop: "{{ presharedkey_files.results }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.item.name }}" |  | ||||||
|   when: item.stat.exists |  | ||||||
|  |  | ||||||
| - name: Grab WireGuard private key for configuration |  | ||||||
|   ansible.builtin.slurp: |  | ||||||
|     src: /etc/wireguard/privatekey |  | ||||||
|   register: wgkey |  | ||||||
|  |  | ||||||
| - name: Install WireGuard configuration | - name: Install WireGuard configuration | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: wireguard.j2 |     src: wireguard.j2 | ||||||
|   | |||||||
| @@ -1,6 +1,4 @@ | |||||||
| # {{ ansible_managed }} | [Interface] | ||||||
|  |  | ||||||
| [Interface] # {{ ansible_hostname }} |  | ||||||
| PrivateKey = {{ wgkey['content'] | b64decode | trim }} | PrivateKey = {{ wgkey['content'] | b64decode | trim }} | ||||||
| Address = {{ wireguard.address }} | Address = {{ wireguard.address }} | ||||||
| {% if wireguard.listenport is defined %} | {% if wireguard.listenport is defined %} | ||||||
| @@ -8,26 +6,8 @@ ListenPort = {{ wireguard.listenport }} | |||||||
| {% endif %} | {% endif %} | ||||||
|  |  | ||||||
| {% for peer in wireguard.peers %} | {% for peer in wireguard.peers %} | ||||||
| {% if peer.name is defined %} |  | ||||||
| [Peer] # {{ peer.name }} |  | ||||||
| {% else %} |  | ||||||
| [Peer] | [Peer] | ||||||
| {% endif %} |  | ||||||
| PublicKey = {{ peer.publickey }} | PublicKey = {{ peer.publickey }} | ||||||
| {% if peer.presharedkey is defined %} |  | ||||||
| PresharedKey = {{ peer.presharedkey }} |  | ||||||
| {% else %} |  | ||||||
| {% set preshared_key = ( |  | ||||||
|     wgshared.results |  | ||||||
|     | selectattr('item.item.name', 'equalto', peer.name) |  | ||||||
|     | first |  | ||||||
|   ).content |  | ||||||
|   | default(none) |  | ||||||
| %} |  | ||||||
| {% if preshared_key is not none %} |  | ||||||
| PresharedKey = {{ preshared_key | b64decode | trim }} |  | ||||||
| {% endif %} |  | ||||||
| {% endif %} |  | ||||||
| {% if peer.endpoint is defined %} | {% if peer.endpoint is defined %} | ||||||
| Endpoint = {{ peer.endpoint }} | Endpoint = {{ peer.endpoint }} | ||||||
| {% endif %} | {% endif %} | ||||||
|   | |||||||
| @@ -24,21 +24,15 @@ | |||||||
|  |  | ||||||
| - name: Install/uninstall Docker from Debian repositories | - name: Install/uninstall Docker from Debian repositories | ||||||
|   ansible.builtin.apt: |   ansible.builtin.apt: | ||||||
|     name: ["docker.io", "docker-compose", "containerd", "runc"] |     name: ['docker.io', 'docker-compose', 'containerd', 'runc'] | ||||||
|     state: "{{ 'absent' if docker_official else 'present' }}" |     state: "{{ 'absent' if docker_official else 'present' }}" | ||||||
|     autoremove: true |     autoremove: true | ||||||
|     update_cache: true |     update_cache: true | ||||||
|  |  | ||||||
| - name: Install/uninstall Docker from Docker repositories | - name: Install/uninstall Docker from Docker repositories | ||||||
|   ansible.builtin.apt: |   ansible.builtin.apt: | ||||||
|     name: |     name: ['docker-ce', 'docker-ce-cli', 'containerd.io', | ||||||
|       [ |            'docker-buildx-plugin', 'docker-compose-plugin'] | ||||||
|         "docker-ce", |  | ||||||
|         "docker-ce-cli", |  | ||||||
|         "containerd.io", |  | ||||||
|         "docker-buildx-plugin", |  | ||||||
|         "docker-compose-plugin", |  | ||||||
|       ] |  | ||||||
|     state: "{{ 'present' if docker_official else 'absent' }}" |     state: "{{ 'present' if docker_official else 'absent' }}" | ||||||
|     autoremove: true |     autoremove: true | ||||||
|     update_cache: true |     update_cache: true | ||||||
| @@ -141,6 +135,14 @@ | |||||||
|     label: "{{ item.name }}" |     label: "{{ item.name }}" | ||||||
|   when: docker_compose_deploy is defined and item.env is defined |   when: docker_compose_deploy is defined and item.env is defined | ||||||
|  |  | ||||||
|  | - name: Add users to docker group | ||||||
|  |   ansible.builtin.user: | ||||||
|  |     name: "{{ item }}" | ||||||
|  |     groups: docker | ||||||
|  |     append: true | ||||||
|  |   loop: "{{ docker_users }}" | ||||||
|  |   when: docker_users is defined | ||||||
|  |  | ||||||
| - name: Start Docker and enable on boot | - name: Start Docker and enable on boot | ||||||
|   ansible.builtin.service: |   ansible.builtin.service: | ||||||
|     name: docker |     name: docker | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ services: | |||||||
|     networks: |     networks: | ||||||
|       - traefik |       - traefik | ||||||
|     labels: |     labels: | ||||||
|       - "traefik.http.routers.{{ jellyfin_router }}.rule=Host({{ jellyfin_domains }})" |       - "traefik.http.routers.{{ jellyfin_router }}.rule=Host(`{{ jellyfin_domain }}`)" | ||||||
| {% if traefik_http_only %} | {% if traefik_http_only %} | ||||||
|       - "traefik.http.routers.{{ jellyfin_router }}.entrypoints=web" |       - "traefik.http.routers.{{ jellyfin_router }}.entrypoints=web" | ||||||
| {% else %} | {% else %} | ||||||
|   | |||||||
| @@ -16,12 +16,10 @@ | |||||||
|     regex: "^bind-address" |     regex: "^bind-address" | ||||||
|     line: "bind-address            = {{ ansible_facts.docker0.ipv4.address }}" |     line: "bind-address            = {{ ansible_facts.docker0.ipv4.address }}" | ||||||
|   notify: restart_mariadb |   notify: restart_mariadb | ||||||
|   when: ansible_facts.docker0 is defined |  | ||||||
|  |  | ||||||
| - name: Flush handlers to ensure MariaDB restarts immediately | - name: Flush handlers to ensure MariaDB restarts immediately | ||||||
|   ansible.builtin.meta: flush_handlers |   ansible.builtin.meta: flush_handlers | ||||||
|   tags: restart_mariadb |   tags: restart_mariadb | ||||||
|   when: ansible_facts.docker0 is defined |  | ||||||
|  |  | ||||||
| - name: Allow database connections from Docker | - name: Allow database connections from Docker | ||||||
|   community.general.ufw: |   community.general.ufw: | ||||||
|   | |||||||
| @@ -1,4 +0,0 @@ | |||||||
| # Default configuration for podman role |  | ||||||
| podman_repos_keytype: ed25519 |  | ||||||
| podman_ssh_key_path: "{{ ansible_user_dir }}/.ssh" |  | ||||||
| podman_nodocker: false |  | ||||||
| @@ -1,54 +0,0 @@ | |||||||
| - name: Reload systemd manager configuration |  | ||||||
|   ansible.builtin.systemd: |  | ||||||
|     daemon_reload: true |  | ||||||
|     scope: user |  | ||||||
|   become: true |  | ||||||
|   become_user: "{{ podman_user }}" |  | ||||||
|   listen: podman_compose_systemd |  | ||||||
|  |  | ||||||
| - name: Find which services had a podman-compose.yml updated |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     podman_compose_restart_list: |  | ||||||
|       "{{ (podman_compose_restart_list | default([])) + [{'user': podman_user, |  | ||||||
|       'service': item.item.name}] }}" |  | ||||||
|   loop: "{{ podman_compose_update.results }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ podman_user }}/{{ item.item.name }}" |  | ||||||
|   when: item.changed |  | ||||||
|   listen: podman_compose_restart |  | ||||||
|  |  | ||||||
| - name: Find which services had their .env updated |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     podman_compose_restart_list: |  | ||||||
|       "{{ (podman_compose_restart_list | default([])) + [{'user': podman_user, |  | ||||||
|       'service': item.item.name}] }}" |  | ||||||
|   loop: "{{ podman_compose_env_update.results }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ podman_user }}/{{ item.item.name }}" |  | ||||||
|   when: item.changed |  | ||||||
|   listen: podman_compose_restart |  | ||||||
|  |  | ||||||
| - name: Restart podman-compose services |  | ||||||
|   ansible.builtin.systemd: |  | ||||||
|     state: restarted |  | ||||||
|     name: "podman-compose@{{ item.service }}" |  | ||||||
|     scope: user |  | ||||||
|   become: true |  | ||||||
|   become_user: "{{ item.user }}" |  | ||||||
|   loop: "{{ podman_compose_restart_list | default([]) | unique }}" |  | ||||||
|   when: podman_compose_restart_list is defined |  | ||||||
|   listen: podman_compose_restart |  | ||||||
|  |  | ||||||
| - name: Start podman-compose services and enable on boot |  | ||||||
|   ansible.builtin.systemd: |  | ||||||
|     name: "podman-compose@{{ item.name }}" |  | ||||||
|     state: started |  | ||||||
|     enabled: true |  | ||||||
|     scope: user |  | ||||||
|   become: true |  | ||||||
|   become_user: "{{ podman_user }}" |  | ||||||
|   loop: "{{ podman_compose }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ podman_user }}/{{ item.name }}" |  | ||||||
|   when: item.enabled is defined and item.enabled is true |  | ||||||
|   listen: podman_compose_enable |  | ||||||
| @@ -1,182 +0,0 @@ | |||||||
| - name: Get user info for podman compose user |  | ||||||
|   ansible.builtin.getent: |  | ||||||
|     database: passwd |  | ||||||
|     key: "{{ podman_user }}" |  | ||||||
|   register: podman_user_info |  | ||||||
|  |  | ||||||
| - name: Set user-specific variables |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     podman_rootdir: "{{ podman_compose_config.root }}" |  | ||||||
|     podman_userid: "{{ podman_user_info.ansible_facts.getent_passwd[podman_user][1] }}" |  | ||||||
|     podman_compose: "{{ podman_compose_config.compose }}" |  | ||||||
|     podman_repos: "{{ podman_compose_config.root }}/.compose_repos" |  | ||||||
|  |  | ||||||
| - name: Create podman-compose root directory for user |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ podman_rootdir }}" |  | ||||||
|     state: directory |  | ||||||
|     owner: "{{ podman_user }}" |  | ||||||
|     group: "{{ podman_user }}" |  | ||||||
|     mode: "0700" |  | ||||||
|  |  | ||||||
| - name: Create user systemd directory |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "/home/{{ podman_user }}/.config/systemd/user" |  | ||||||
|     state: directory |  | ||||||
|     owner: "{{ podman_user }}" |  | ||||||
|     group: "{{ podman_user }}" |  | ||||||
|     mode: "0755" |  | ||||||
|  |  | ||||||
| - name: Install podman-compose systemd service for user |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: podman-compose.service.j2 |  | ||||||
|     dest: "/home/{{ podman_user }}/.config/systemd/user/podman-compose@.service" |  | ||||||
|     owner: "{{ podman_user }}" |  | ||||||
|     group: "{{ podman_user }}" |  | ||||||
|     mode: "0644" |  | ||||||
|   notify: podman_compose_systemd |  | ||||||
|  |  | ||||||
| - name: Create directories for cloning podman-compose repositories |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ repo_dir }}" |  | ||||||
|     state: directory |  | ||||||
|     owner: "{{ podman_user }}" |  | ||||||
|     group: "{{ podman_user }}" |  | ||||||
|     mode: "0700" |  | ||||||
|   loop: |  | ||||||
|     - "{{ podman_repos }}" |  | ||||||
|   loop_control: |  | ||||||
|     loop_var: repo_dir |  | ||||||
|   when: |  | ||||||
|     - podman_compose is defined |  | ||||||
|     - podman_compose | length > 0 |  | ||||||
|  |  | ||||||
| - name: Create .ssh directory for podman compose user |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ podman_ssh_key_path }}" |  | ||||||
|     state: directory |  | ||||||
|     owner: "{{ podman_user }}" |  | ||||||
|     group: "{{ podman_user }}" |  | ||||||
|     mode: "0700" |  | ||||||
|   when: |  | ||||||
|     - podman_compose is defined |  | ||||||
|     - podman_compose | length > 0 |  | ||||||
|  |  | ||||||
| - name: Generate OpenSSH deploy keys for podman-compose clones |  | ||||||
|   community.crypto.openssh_keypair: |  | ||||||
|     path: "{{ podman_ssh_key_path }}/podman-id_{{ podman_repos_keytype }}" |  | ||||||
|     type: "{{ podman_repos_keytype }}" |  | ||||||
|     comment: "{{ ansible_hostname }}-{{ podman_user }}-deploy-key" |  | ||||||
|     owner: "{{ podman_user }}" |  | ||||||
|     group: "{{ podman_user }}" |  | ||||||
|     mode: "0600" |  | ||||||
|     state: present |  | ||||||
|   when: podman_compose is defined |  | ||||||
|  |  | ||||||
| - name: Import trusted GPG keys for podman-compose projects |  | ||||||
|   ansible.builtin.command: |  | ||||||
|     cmd: "gpg --keyserver {{ key.keyserver | default('keys.openpgp.org') }} --recv-key {{ key.id }}" |  | ||||||
|   become: true |  | ||||||
|   become_user: "{{ podman_user }}" |  | ||||||
|   loop: "{{ podman_compose_config.trusted_keys }}" |  | ||||||
|   loop_control: |  | ||||||
|     loop_var: key |  | ||||||
|     label: "{{ key.id }}" |  | ||||||
|   changed_when: false |  | ||||||
|   when: podman_compose_config.trusted_keys is defined |  | ||||||
|  |  | ||||||
| - name: Clone external podman-compose projects |  | ||||||
|   ansible.builtin.git: |  | ||||||
|     repo: "{{ project.url }}" |  | ||||||
|     dest: "{{ podman_repos }}/{{ project.name }}" |  | ||||||
|     version: "{{ project.version }}" |  | ||||||
|     accept_newhostkey: "{{ project.accept_newhostkey | default(false) }}" |  | ||||||
|     gpg_whitelist: "{{ (project.trusted_keys | default(podman_compose_config.trusted_keys | default([]))) | map(attribute='id') | list }}" |  | ||||||
|     verify_commit: >- |  | ||||||
|       {{ true if (project.trusted_keys is defined and project.trusted_keys) or |  | ||||||
|          (podman_compose_config.trusted_keys is defined and podman_compose_config.trusted_keys) |  | ||||||
|          else false }} |  | ||||||
|     key_file: "{{ podman_ssh_key_path }}/podman-id_{{ podman_repos_keytype }}" |  | ||||||
|   become: true |  | ||||||
|   become_user: "{{ podman_user }}" |  | ||||||
|   loop: "{{ podman_compose }}" |  | ||||||
|   loop_control: |  | ||||||
|     loop_var: project |  | ||||||
|     label: "{{ project.url }}" |  | ||||||
|   when: |  | ||||||
|     - podman_compose is defined |  | ||||||
|     - podman_compose | length > 0 |  | ||||||
|  |  | ||||||
| - name: Create directories for podman-compose projects |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ podman_rootdir }}/{{ project.name }}" |  | ||||||
|     state: directory |  | ||||||
|     owner: "{{ podman_user }}" |  | ||||||
|     group: "{{ podman_user }}" |  | ||||||
|     mode: "0700" |  | ||||||
|   loop: "{{ podman_compose }}" |  | ||||||
|   loop_control: |  | ||||||
|     loop_var: project |  | ||||||
|     label: "{{ project.name }}" |  | ||||||
|   when: |  | ||||||
|     - podman_compose is defined |  | ||||||
|     - podman_compose | length > 0 |  | ||||||
|  |  | ||||||
| - name: Synchronize podman-compose.yml (or docker-compose.yml) |  | ||||||
|   ansible.posix.synchronize: |  | ||||||
|     src: "{{ podman_repos }}/{{ project.name }}/{{ project.path | default('docker-compose.yml') }}" |  | ||||||
|     dest: "{{ podman_rootdir }}/{{ project.name }}/docker-compose.yml" |  | ||||||
|     owner: false |  | ||||||
|     group: false |  | ||||||
|   delegate_to: "{{ inventory_hostname }}" |  | ||||||
|   register: podman_compose_update |  | ||||||
|   notify: |  | ||||||
|     - podman_compose_restart |  | ||||||
|     - podman_compose_enable |  | ||||||
|   loop: "{{ podman_compose | default([]) }}" |  | ||||||
|   loop_control: |  | ||||||
|     loop_var: project |  | ||||||
|     label: "{{ project.name }}" |  | ||||||
|   when: |  | ||||||
|     - podman_compose is defined |  | ||||||
|     - podman_compose | length > 0 |  | ||||||
|  |  | ||||||
| - name: Fix ownership of synchronized compose files |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ podman_rootdir }}/{{ project.name }}/docker-compose.yml" |  | ||||||
|     owner: "{{ podman_user }}" |  | ||||||
|     group: "{{ podman_user }}" |  | ||||||
|     mode: "0600" |  | ||||||
|   loop: "{{ podman_compose | default([]) }}" |  | ||||||
|   loop_control: |  | ||||||
|     loop_var: project |  | ||||||
|     label: "{{ project.name }}" |  | ||||||
|   when: |  | ||||||
|     - podman_compose is defined |  | ||||||
|     - podman_compose | length > 0 |  | ||||||
|  |  | ||||||
| - name: Set environment variables for podman-compose projects |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: podman-compose-env.j2 |  | ||||||
|     dest: "{{ podman_rootdir }}/{{ project.name }}/.env" |  | ||||||
|     owner: "{{ podman_user }}" |  | ||||||
|     group: "{{ podman_user }}" |  | ||||||
|     mode: "0600" |  | ||||||
|   register: podman_compose_env_update |  | ||||||
|   notify: |  | ||||||
|     - podman_compose_restart |  | ||||||
|     - podman_compose_enable |  | ||||||
|   no_log: true |  | ||||||
|   loop: "{{ podman_compose }}" |  | ||||||
|   loop_control: |  | ||||||
|     loop_var: project |  | ||||||
|     label: "{{ project.name }}" |  | ||||||
|   when: podman_compose is defined and project.env is defined |  | ||||||
|  |  | ||||||
| - name: Enable lingering for podman compose user |  | ||||||
|   ansible.builtin.command: |  | ||||||
|     cmd: "loginctl enable-linger {{ podman_user }}" |  | ||||||
|   changed_when: false |  | ||||||
|   when: |  | ||||||
|     - podman_compose is defined |  | ||||||
|     - podman_compose | length > 0 |  | ||||||
| @@ -1,77 +0,0 @@ | |||||||
| - name: Install Podman |  | ||||||
|   ansible.builtin.apt: |  | ||||||
|     name: ["podman", "podman-compose", "podman-docker"] |  | ||||||
|     state: present |  | ||||||
|  |  | ||||||
| - name: Get user info for namespace users |  | ||||||
|   ansible.builtin.getent: |  | ||||||
|     database: passwd |  | ||||||
|     key: "{{ item }}" |  | ||||||
|   loop: "{{ user_namespaces }}" |  | ||||||
|   register: user_info |  | ||||||
|  |  | ||||||
| - name: Configure /etc/subuid for rootless users |  | ||||||
|   ansible.builtin.lineinfile: |  | ||||||
|     path: "/etc/subuid" |  | ||||||
|     line: |  | ||||||
|       "{{ item.item }}:{{ 100000 + |  | ||||||
|       ((item.ansible_facts.getent_passwd[item.item][1] | int - 1000) * 65536) |  | ||||||
|       }}:65536" |  | ||||||
|     regexp: "^{{ item.item }}:" |  | ||||||
|     create: true |  | ||||||
|     backup: true |  | ||||||
|     mode: "0644" |  | ||||||
|   loop: "{{ user_info.results }}" |  | ||||||
|  |  | ||||||
| - name: Configure /etc/subgid for rootless users |  | ||||||
|   ansible.builtin.lineinfile: |  | ||||||
|     path: "/etc/subgid" |  | ||||||
|     line: |  | ||||||
|       "{{ item.item }}:{{ 100000 + |  | ||||||
|       ((item.ansible_facts.getent_passwd[item.item][1] | int - 1000) * 65536) |  | ||||||
|       }}:65536" |  | ||||||
|     regexp: "^{{ item.item }}:" |  | ||||||
|     create: true |  | ||||||
|     backup: true |  | ||||||
|     mode: "0644" |  | ||||||
|   loop: "{{ user_info.results }}" |  | ||||||
|  |  | ||||||
| - name: Create nodocker file to disable Docker CLI emulation message |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: /etc/containers/nodocker |  | ||||||
|     state: touch |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: "0644" |  | ||||||
|   when: podman_nodocker | bool |  | ||||||
|  |  | ||||||
| - name: Create global containers config directory |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: /etc/containers |  | ||||||
|     state: directory |  | ||||||
|     mode: "0755" |  | ||||||
|  |  | ||||||
| - name: Configure global containers.conf for rootless |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     content: | |  | ||||||
|       [engine] |  | ||||||
|       cgroup_manager = "cgroupfs" |  | ||||||
|       events_logger = "journald" |  | ||||||
|       runtime = "crun" |  | ||||||
|     dest: /etc/containers/containers.conf |  | ||||||
|     mode: "0644" |  | ||||||
|     backup: true |  | ||||||
|  |  | ||||||
| - name: Install git for repository cloning |  | ||||||
|   ansible.builtin.apt: |  | ||||||
|     name: git |  | ||||||
|     state: present |  | ||||||
|   when: podman_compose_deploy is defined |  | ||||||
|  |  | ||||||
| - name: Deploy Podman compose projects for each user |  | ||||||
|   ansible.builtin.include_tasks: deploy.yml |  | ||||||
|   vars: |  | ||||||
|     podman_user: "{{ item.key }}" |  | ||||||
|     podman_compose_config: "{{ item.value }}" |  | ||||||
|   loop: "{{ podman_compose_deploy | dict2items }}" |  | ||||||
|   when: podman_compose_deploy is defined |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| # {{ ansible_managed }} |  | ||||||
| {% if item.env is defined %} |  | ||||||
| {% for key, value in item.env.items() %} |  | ||||||
| {% if value is boolean %} |  | ||||||
| {{ key }}={{ value | lower }} |  | ||||||
| {% else %} |  | ||||||
| {{ key }}={{ value }} |  | ||||||
| {% endif %} |  | ||||||
| {% endfor %} |  | ||||||
| {% endif %} |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| [Unit] |  | ||||||
| Description=%i podman-compose service for {{ podman_user }} |  | ||||||
| After=network-online.target |  | ||||||
| Wants=network-online.target |  | ||||||
|  |  | ||||||
| [Service] |  | ||||||
| Type=oneshot |  | ||||||
| RemainAfterExit=true |  | ||||||
| WorkingDirectory={{ podman_rootdir }}/%i |  | ||||||
| ExecStart=/usr/bin/podman-compose up -d --remove-orphans |  | ||||||
| ExecStop=/usr/bin/podman-compose down |  | ||||||
| Environment="PODMAN_USERNS=keep-id" |  | ||||||
| Environment="PODMAN_SOCKET_PATH=/run/user/{{ podman_userid }}/podman/podman.sock" |  | ||||||
| TimeoutStartSec=0 |  | ||||||
|  |  | ||||||
| [Install] |  | ||||||
| WantedBy=default.target |  | ||||||
| @@ -45,8 +45,7 @@ | |||||||
|   register: nginx_sites |   register: nginx_sites | ||||||
|  |  | ||||||
| - name: Generate self-signed certificate | - name: Generate self-signed certificate | ||||||
|   ansible.builtin.command: |   ansible.builtin.command: 'openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes \ | ||||||
|     'openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes \ |  | ||||||
|           -subj   "/C=US/ST=Local/L=Local/O=Org/OU=IT/CN=example.com" \ |           -subj   "/C=US/ST=Local/L=Local/O=Org/OU=IT/CN=example.com" \ | ||||||
|           -keyout /etc/ssl/private/nginx-selfsigned.key \ |           -keyout /etc/ssl/private/nginx-selfsigned.key \ | ||||||
|           -out    /etc/ssl/certs/nginx-selfsigned.crt' |           -out    /etc/ssl/certs/nginx-selfsigned.crt' | ||||||
| @@ -57,22 +56,15 @@ | |||||||
|  |  | ||||||
| - name: Install LE's certbot | - name: Install LE's certbot | ||||||
|   ansible.builtin.apt: |   ansible.builtin.apt: | ||||||
|     name: ["certbot", "python3-certbot-dns-cloudflare"] |     name: ['certbot', 'python3-certbot-dns-cloudflare'] | ||||||
|     state: present |     state: present | ||||||
|   when: proxy.production is defined and proxy.production |   when: proxy.production is defined and proxy.production | ||||||
|  |  | ||||||
| - name: Grab Cloudflare API token for configuration |  | ||||||
|   ansible.builtin.slurp: |  | ||||||
|     src: /root/.cloudflare-api |  | ||||||
|   register: cfapi |  | ||||||
|   when: proxy.production is defined and proxy.production and proxy.dns_cloudflare is defined |  | ||||||
|  |  | ||||||
| - name: Install Cloudflare API token | - name: Install Cloudflare API token | ||||||
|   ansible.builtin.template: |   ansible.builtin.template: | ||||||
|     src: cloudflare.ini.j2 |     src: cloudflare.ini.j2 | ||||||
|     dest: /root/.cloudflare.ini |     dest: /root/.cloudflare.ini | ||||||
|     mode: "400" |     mode: "400" | ||||||
|   diff: false |  | ||||||
|   when: proxy.production is defined and proxy.production and proxy.dns_cloudflare is defined |   when: proxy.production is defined and proxy.production and proxy.dns_cloudflare is defined | ||||||
|  |  | ||||||
| - name: Create nginx post renewal hook directory | - name: Create nginx post renewal hook directory | ||||||
| @@ -86,7 +78,7 @@ | |||||||
|   ansible.builtin.copy: |   ansible.builtin.copy: | ||||||
|     src: reload-nginx.sh |     src: reload-nginx.sh | ||||||
|     dest: /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh |     dest: /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh | ||||||
|     mode: "0755" |     mode: '0755' | ||||||
|   when: proxy.production is defined and proxy.production |   when: proxy.production is defined and proxy.production | ||||||
|  |  | ||||||
| - name: Run Cloudflare DNS-01 challenges on wildcard domains | - name: Run Cloudflare DNS-01 challenges on wildcard domains | ||||||
|   | |||||||
| @@ -1,2 +1,2 @@ | |||||||
| # Cloudflare API token used by Certbot | # Cloudflare API token used by Certbot | ||||||
| dns_cloudflare_api_token = {{ cfapi['content'] | b64decode | trim }} | dns_cloudflare_api_token = {{ proxy.dns_cloudflare.api_token }} | ||||||
|   | |||||||
| @@ -28,19 +28,13 @@ server { | |||||||
|   ssl_certificate     /etc/ssl/certs/nginx-selfsigned.crt; |   ssl_certificate     /etc/ssl/certs/nginx-selfsigned.crt; | ||||||
|   ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; |   ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; | ||||||
| {% endif %} | {% endif %} | ||||||
|  | {% if item.hsts is defined %} | ||||||
|  |   add_header Strict-Transport-Security "max-age={{ item.hsts }}" always; | ||||||
|  | {% endif %} | ||||||
| {% if item.client_max_body_size is defined %} | {% if item.client_max_body_size is defined %} | ||||||
|   client_max_body_size {{ item.client_max_body_size }}; |   client_max_body_size {{ item.client_max_body_size }}; | ||||||
| {% endif %} | {% endif %} | ||||||
|   location / { |   location / { | ||||||
| {% if item.hsts is defined %} |  | ||||||
|     add_header Strict-Transport-Security "max-age={{ item.hsts }}" always; |  | ||||||
| {% endif %} |  | ||||||
| {% if item.allowedips is defined %} |  | ||||||
| {% for ip in item.allowedips %} |  | ||||||
|     allow {{ ip }}; |  | ||||||
| {% endfor %} |  | ||||||
|     deny all; |  | ||||||
| {% endif %} |  | ||||||
| {% if item.restrict is defined and item.restrict  %} | {% if item.restrict is defined and item.restrict  %} | ||||||
|     auth_basic "{{ item.restrict_name | default('Restricted Access') }}"; |     auth_basic "{{ item.restrict_name | default('Restricted Access') }}"; | ||||||
|     auth_basic_user_file {{ item.restrict_file | default('/etc/nginx/.htpasswd') }}; |     auth_basic_user_file {{ item.restrict_file | default('/etc/nginx/.htpasswd') }}; | ||||||
| @@ -49,7 +43,6 @@ server { | |||||||
|     proxy_set_header Host $host; |     proxy_set_header Host $host; | ||||||
|     proxy_set_header X-Real-IP $remote_addr; |     proxy_set_header X-Real-IP $remote_addr; | ||||||
|     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||||||
|     proxy_set_header X-Forwarded-Proto $scheme; |  | ||||||
|     proxy_pass {{ item.proxy_pass }}; |     proxy_pass {{ item.proxy_pass }}; | ||||||
| {% if item.proxy_ssl_verify is defined and item.proxy_ssl_verify is false %} | {% if item.proxy_ssl_verify is defined and item.proxy_ssl_verify is false %} | ||||||
|     proxy_ssl_verify off; |     proxy_ssl_verify off; | ||||||
|   | |||||||
							
								
								
									
										45
									
								
								scripts/github-vagrant.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										45
									
								
								scripts/github-vagrant.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | #!/bin/bash | ||||||
|  |  | ||||||
|  | # Defaults | ||||||
|  | TIMEOUT=600 | ||||||
|  | ELAPSED=0 | ||||||
|  | INITIAL_SLEEP=60 | ||||||
|  | SLEEP_DURATION=30 | ||||||
|  | SSH_AVAILABLE=0 | ||||||
|  | DEBUG_ID="[homelab-ci]" | ||||||
|  |  | ||||||
|  | # Run Vagrant Up in the background | ||||||
|  | PLAYBOOK=dockerbox vagrant up & | ||||||
|  | VAGRANT_UP_PID=$! | ||||||
|  |  | ||||||
|  | # Initial delay | ||||||
|  | echo "$DEBUG_ID Waiting for VM to start..." | ||||||
|  | sleep $INITIAL_SLEEP | ||||||
|  |  | ||||||
|  | # Loop until timeout or breaks | ||||||
|  | while [[ $ELAPSED -lt $TIMEOUT ]]; do | ||||||
|  | 	VAGRANT_SSH_CONFIG=$(mktemp) | ||||||
|  | 	vagrant ssh-config > "$VAGRANT_SSH_CONFIG" | ||||||
|  | 	echo "$DEBUG_ID SSH config at $VAGRANT_SSH_CONFIG" | ||||||
|  | 	cat "$VAGRANT_SSH_CONFIG" | ||||||
|  | 	echo "$DEBUG_ID Vagrant status" | ||||||
|  | 	vagrant status | ||||||
|  |  | ||||||
|  | 	# SSH attempt | ||||||
|  | 	set -x | ||||||
|  | 	ssh -vvv -F "$VAGRANT_SSH_CONFIG" default 'cat /etc/os-release' && set +x; break \ | ||||||
|  | 	|| echo "$DEBUG_ID SSH connection failed, retrying in $SLEEP_DURATION seconds..." | ||||||
|  | 	set +x | ||||||
|  |  | ||||||
|  | 	# Sleep and start again | ||||||
|  | 	sleep $SLEEP_DURATION | ||||||
|  | 	((ELAPSED+=SLEEP_DURATION)) | ||||||
|  | done | ||||||
|  |  | ||||||
|  | # Success? | ||||||
|  | if [[ $SSH_AVAILABLE -ne 1 ]]; then | ||||||
|  | 	echo "$DEBUG_ID Timeout reached without successful SSH connection." | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # Ensure the Vagrant up process completes | ||||||
|  | wait $VAGRANT_UP_PID | ||||||
		Reference in New Issue
	
	Block a user