Ansible ins Repo migrieren und zentrale SSH-Keys in shared/ssh.
Playbooks liegen unter pve1/ansible und pve2/ansible; authorized_keys als Fragmente mit Deploy-Skript und Ziel-Matrix für Proxmox, VM 101 und CTs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
|||||||
|
# Ansible auf pve1
|
||||||
|
|
||||||
|
Kleine Playbooks, die **von pve1** aus laufen (nicht die pve2 CT-Wartung).
|
||||||
|
|
||||||
|
| Datei | Zweck |
|
||||||
|
|-------|--------|
|
||||||
|
| [fish-setup.yml](fish-setup.yml) | Fish + bobthefish auf VM 101 (`jean`) |
|
||||||
|
| [inventory.ini](inventory.ini) | Inventory für fish-setup |
|
||||||
|
|
||||||
|
## Ausführen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /root/docu/pve1/ansible # oder: /root/ansible → Symlink
|
||||||
|
ansible-playbook -i inventory.ini fish-setup.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deploy-Pfad auf dem Host
|
||||||
|
|
||||||
|
Empfohlen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ln -sfn /root/docu/pve1/ansible /root/ansible
|
||||||
|
```
|
||||||
|
|
||||||
|
## SSH-Keys
|
||||||
|
|
||||||
|
Inventory nutzt `ansible_user=jean` auf `192.168.10.10` — Keys siehe [../../shared/ssh/README.md](../../shared/ssh/README.md).
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
---
|
||||||
|
- name: Install and configure fish shell with bobthefish
|
||||||
|
hosts: servers
|
||||||
|
become: true
|
||||||
|
|
||||||
|
vars:
|
||||||
|
target_user: jean
|
||||||
|
fisher_url: https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Install fish shell
|
||||||
|
apt:
|
||||||
|
name: fish
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Set fish as default shell for {{ target_user }}
|
||||||
|
user:
|
||||||
|
name: "{{ target_user }}"
|
||||||
|
shell: /usr/bin/fish
|
||||||
|
|
||||||
|
- name: Create fish config directory
|
||||||
|
file:
|
||||||
|
path: /home/{{ target_user }}/.config/fish/functions
|
||||||
|
state: directory
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Install Fisher plugin manager
|
||||||
|
become_user: "{{ target_user }}"
|
||||||
|
shell: |
|
||||||
|
curl -sL {{ fisher_url }} | source && fisher install jorgebucaran/fisher
|
||||||
|
args:
|
||||||
|
executable: /usr/bin/fish
|
||||||
|
creates: /home/{{ target_user }}/.config/fish/functions/fisher.fish
|
||||||
|
|
||||||
|
- name: Install bobthefish theme
|
||||||
|
become_user: "{{ target_user }}"
|
||||||
|
shell: |
|
||||||
|
fisher install oh-my-fish/theme-bobthefish
|
||||||
|
args:
|
||||||
|
executable: /usr/bin/fish
|
||||||
|
register: bobthefish_install
|
||||||
|
changed_when: "'Installing' in bobthefish_install.stdout"
|
||||||
|
|
||||||
|
- name: Configure bobthefish in config.fish
|
||||||
|
become_user: "{{ target_user }}"
|
||||||
|
blockinfile:
|
||||||
|
path: /home/{{ target_user }}/.config/fish/config.fish
|
||||||
|
create: true
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
mode: "0644"
|
||||||
|
marker: "# {mark} ANSIBLE MANAGED - bobthefish config"
|
||||||
|
block: |
|
||||||
|
set -g theme_color_scheme nord
|
||||||
|
set -g theme_display_git yes
|
||||||
|
set -g theme_display_git_dirty yes
|
||||||
|
set -g theme_display_git_untracked yes
|
||||||
|
set -g theme_git_worktree_support no
|
||||||
|
set -g theme_display_vagrant no
|
||||||
|
set -g theme_display_docker_machine no
|
||||||
|
set -g theme_display_k8s_context no
|
||||||
|
set -g theme_display_user ssh
|
||||||
|
set -g theme_display_hostname ssh
|
||||||
|
set -g theme_show_exit_status yes
|
||||||
|
set -g theme_title_use_abbreviated_path yes
|
||||||
|
set -g fish_greeting ""
|
||||||
|
|
||||||
|
- name: Install Nerd Font (JetBrainsMono) for powerline glyphs
|
||||||
|
block:
|
||||||
|
- name: Create fonts directory
|
||||||
|
file:
|
||||||
|
path: /home/{{ target_user }}/.local/share/fonts
|
||||||
|
state: directory
|
||||||
|
owner: "{{ target_user }}"
|
||||||
|
group: "{{ target_user }}"
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Download JetBrainsMono Nerd Font
|
||||||
|
become_user: "{{ target_user }}"
|
||||||
|
get_url:
|
||||||
|
url: https://github.com/ryanoasis/nerd-fonts/releases/download/v3.2.1/JetBrainsMono.zip
|
||||||
|
dest: /tmp/JetBrainsMono.zip
|
||||||
|
timeout: 60
|
||||||
|
|
||||||
|
- name: Install unzip
|
||||||
|
apt:
|
||||||
|
name: unzip
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Unzip Nerd Font
|
||||||
|
become_user: "{{ target_user }}"
|
||||||
|
unarchive:
|
||||||
|
src: /tmp/JetBrainsMono.zip
|
||||||
|
dest: /home/{{ target_user }}/.local/share/fonts/
|
||||||
|
remote_src: true
|
||||||
|
creates: /home/{{ target_user }}/.local/share/fonts/JetBrainsMonoNerdFont-Regular.ttf
|
||||||
|
|
||||||
|
- name: Install fontconfig
|
||||||
|
apt:
|
||||||
|
name: fontconfig
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Rebuild font cache
|
||||||
|
become_user: "{{ target_user }}"
|
||||||
|
command: fc-cache -f
|
||||||
|
changed_when: true
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[servers]
|
||||||
|
192.168.10.10 ansible_user=jean ansible_become=true
|
||||||
@@ -14,17 +14,25 @@ Stattdessen:
|
|||||||
```
|
```
|
||||||
/etc/cron.weekly/pve-lxc-disk-maintenance
|
/etc/cron.weekly/pve-lxc-disk-maintenance
|
||||||
↓ (Symlink)
|
↓ (Symlink)
|
||||||
/root/ansible/run-disk-maintenance.sh
|
/root/ansible/run-disk-maintenance.sh ← Symlink nach /root/docu/pve2/ansible
|
||||||
↓
|
↓
|
||||||
ansible-playbook playbooks/disk-maintenance.yml
|
ansible-playbook playbooks/disk-maintenance.yml
|
||||||
↓ SSH
|
↓ SSH
|
||||||
docker (101) · media (109) · AIDEV (110)
|
docker (101) · media (109) · AIDEV (110)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Verzeichnisstruktur
|
## Verzeichnisstruktur (Git)
|
||||||
|
|
||||||
|
Quelle im Repo **`docu`**, auf pve2 deployen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /root/docu && git pull
|
||||||
|
ln -sfn /root/docu/pve2/ansible /root/ansible
|
||||||
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
/root/ansible/
|
/root/docu/pve2/ansible/ # (= /root/ansible nach Symlink)
|
||||||
|
├── README.md
|
||||||
├── ansible.cfg
|
├── ansible.cfg
|
||||||
├── run-disk-maintenance.sh → von cron.weekly aufgerufen
|
├── run-disk-maintenance.sh → von cron.weekly aufgerufen
|
||||||
├── inventory/
|
├── inventory/
|
||||||
@@ -39,6 +47,8 @@ ansible-playbook playbooks/disk-maintenance.yml
|
|||||||
└── handlers/main.yml
|
└── handlers/main.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
SSH-Keys für Ansible → [../shared/ssh/README.md](../shared/ssh/README.md)
|
||||||
|
|
||||||
## Verwaltete Hosts
|
## Verwaltete Hosts
|
||||||
|
|
||||||
| Ansible-Host | VMID | IP | Besonderheiten |
|
| Ansible-Host | VMID | IP | Besonderheiten |
|
||||||
@@ -47,7 +57,7 @@ ansible-playbook playbooks/disk-maintenance.yml
|
|||||||
| media | 109 | 192.168.20.6 | Jellyfin-Cache-Pfad |
|
| media | 109 | 192.168.20.6 | Jellyfin-Cache-Pfad |
|
||||||
| aidev | 110 | 10.100.2.13 | Dev-Tooling optional |
|
| aidev | 110 | 10.100.2.13 | Dev-Tooling optional |
|
||||||
|
|
||||||
SSH als `root` vom Proxmox-Host — Key-Auth war bereits eingerichtet.
|
SSH als `root` vom Proxmox-Host — Public Key `root@pve2` muss in den CTs stehen ([shared/ssh](../shared/ssh/README.md)).
|
||||||
|
|
||||||
## Was das Playbook macht
|
## Was das Playbook macht
|
||||||
|
|
||||||
@@ -101,7 +111,7 @@ echo '0 3 * * * root /root/ansible/run-disk-maintenance.sh' > /etc/cron.d/pve-lx
|
|||||||
|
|
||||||
## Konfiguration anpassen
|
## Konfiguration anpassen
|
||||||
|
|
||||||
Globale Werte: `/root/ansible/inventory/group_vars/all.yml`
|
Globale Werte: `/root/docu/pve2/ansible/inventory/group_vars/all.yml` (oder `/root/ansible/…` via Symlink)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
journal_max_size: 200M
|
journal_max_size: 200M
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Ansible auf pve2 — LXC Disk Maintenance
|
||||||
|
|
||||||
|
Wöchentliche Wartung für CTs **101 docker**, **109 media**, **110 AIDEV** per SSH vom Proxmox-Host.
|
||||||
|
|
||||||
|
| Pfad | Inhalt |
|
||||||
|
|------|--------|
|
||||||
|
| [ansible.cfg](ansible.cfg) | Defaults |
|
||||||
|
| [inventory/hosts.yml](inventory/hosts.yml) | Hosts + CT-Variablen |
|
||||||
|
| [inventory/group_vars/all.yml](inventory/group_vars/all.yml) | Schwellwerte |
|
||||||
|
| [playbooks/disk-maintenance.yml](playbooks/disk-maintenance.yml) | Playbook |
|
||||||
|
| [roles/disk_cleanup/](roles/disk_cleanup/) | Tasks (Journal, Docker, fstrim, …) |
|
||||||
|
| [run-disk-maintenance.sh](run-disk-maintenance.sh) | Cron-Einstieg |
|
||||||
|
|
||||||
|
Doku: [../06_Ansible-Automatisierung.md](../06_Ansible-Automatisierung.md)
|
||||||
|
|
||||||
|
## Ausführen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /root/docu/pve2/ansible # oder: /root/ansible → Symlink
|
||||||
|
./run-disk-maintenance.sh
|
||||||
|
# oder
|
||||||
|
ansible-playbook playbooks/disk-maintenance.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cron (pve2)
|
||||||
|
|
||||||
|
```text
|
||||||
|
/etc/cron.weekly/pve-lxc-disk-maintenance → /root/ansible/run-disk-maintenance.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Nach Symlink auf dieses Verzeichnis bleibt der Cron gültig.
|
||||||
|
|
||||||
|
## Deploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /root/docu && git pull
|
||||||
|
ln -sfn /root/docu/pve2/ansible /root/ansible
|
||||||
|
```
|
||||||
|
|
||||||
|
## SSH
|
||||||
|
|
||||||
|
Ansible verbindet als **root** zu den CTs — Host-Key `root@pve2` muss in CT `authorized_keys` stehen → [../../shared/ssh/README.md](../../shared/ssh/README.md).
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[defaults]
|
||||||
|
inventory = inventory/hosts.yml
|
||||||
|
roles_path = roles
|
||||||
|
remote_user = root
|
||||||
|
host_key_checking = False
|
||||||
|
retry_files_enabled = False
|
||||||
|
gathering = implicit
|
||||||
|
stdout_callback = yaml
|
||||||
|
interpreter_python = auto_silent
|
||||||
|
|
||||||
|
[privilege_escaping]
|
||||||
|
paramiko = ansible.paramiko_ssh.paramiko_ssh
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
# Disk maintenance defaults — tune per host in inventory if needed
|
||||||
|
disk_maintenance_enabled: true
|
||||||
|
|
||||||
|
# systemd journal
|
||||||
|
journal_max_size: 200M
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
docker_prune_stopped_containers_older_than: 168h # 7 days
|
||||||
|
docker_prune_dangling_images: true
|
||||||
|
docker_prune_unused_images_older_than: 336h # 14 days (aggressive tag)
|
||||||
|
docker_prune_build_cache_older_than: 336h
|
||||||
|
docker_prune_dangling_volumes: true
|
||||||
|
docker_log_truncate_threshold: 50M
|
||||||
|
docker_log_truncate_target: 10M
|
||||||
|
|
||||||
|
# LVM thin provisioning — critical on Proxmox local-lvm / nvme_second
|
||||||
|
fstrim_enabled: true
|
||||||
|
|
||||||
|
# Frigate recordings on docker CT (matches config.yaml retain.days: 30)
|
||||||
|
frigate_recordings_retain_days: 30
|
||||||
|
frigate_clips_retain_days: 14
|
||||||
|
|
||||||
|
# Jellyfin transcode/image cache (not metadata — that is library artwork)
|
||||||
|
jellyfin_cache_max_age_days: 30
|
||||||
|
|
||||||
|
# Optional dev tooling (AIDEV)
|
||||||
|
npm_cache_clean: false
|
||||||
|
apt_clean: true
|
||||||
|
|
||||||
|
# Alert thresholds for summary output
|
||||||
|
disk_warn_percent: 80
|
||||||
|
thin_pool_warn_percent: 85
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
all:
|
||||||
|
children:
|
||||||
|
lxc_containers:
|
||||||
|
hosts:
|
||||||
|
docker:
|
||||||
|
ansible_host: 192.168.10.101
|
||||||
|
proxmox_vmid: 101
|
||||||
|
frigate_recordings_path: /mnt/records/recordings
|
||||||
|
frigate_clips_path: /mnt/records/clips
|
||||||
|
media:
|
||||||
|
ansible_host: 192.168.20.6
|
||||||
|
proxmox_vmid: 109
|
||||||
|
jellyfin_cache_path: /opt/stacks/jellyfin/config/cache
|
||||||
|
aidev:
|
||||||
|
ansible_host: 10.100.2.13
|
||||||
|
proxmox_vmid: 110
|
||||||
|
dev_tooling_cleanup: true
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
# Weekly disk maintenance for Proxmox LXC containers
|
||||||
|
# Run from the Proxmox host: ansible-playbook playbooks/disk-maintenance.yml
|
||||||
|
#
|
||||||
|
# Tags:
|
||||||
|
# aggressive — also prune unused images older than 14 days
|
||||||
|
# frigate — enforce recording/clip retention on docker CT
|
||||||
|
# jellyfin — clean stale transcode/image cache on media CT
|
||||||
|
# dev-tooling — npm cache clean on AIDEV (off by default)
|
||||||
|
|
||||||
|
- name: LXC disk maintenance
|
||||||
|
hosts: lxc_containers
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
vars:
|
||||||
|
disk_maintenance_enabled: true
|
||||||
|
roles:
|
||||||
|
- role: disk_cleanup
|
||||||
|
when: disk_maintenance_enabled | bool
|
||||||
|
|
||||||
|
- name: Report Proxmox thin pool usage
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
gather_facts: false
|
||||||
|
tasks:
|
||||||
|
- name: Get LVM thin pool stats
|
||||||
|
ansible.builtin.shell: lvs pve/data nvme_second/nvme_second -o vg_name,lv_name,data_percent 2>/dev/null --noheadings
|
||||||
|
register: thin_pools
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Thin pool summary
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: |
|
||||||
|
Proxmox thin pools after maintenance:
|
||||||
|
{{ thin_pools.stdout }}
|
||||||
|
|
||||||
|
Schedule: see /etc/cron.weekly/pve-lxc-disk-maintenance
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
journal_max_size: 200M
|
||||||
|
docker_prune_stopped_containers_older_than: 168h
|
||||||
|
docker_prune_dangling_images: true
|
||||||
|
docker_prune_unused_images_older_than: 336h
|
||||||
|
docker_prune_build_cache_older_than: 336h
|
||||||
|
docker_prune_dangling_volumes: true
|
||||||
|
docker_log_truncate_threshold: 50M
|
||||||
|
docker_log_truncate_target: 10M
|
||||||
|
fstrim_enabled: true
|
||||||
|
frigate_recordings_retain_days: 30
|
||||||
|
frigate_clips_retain_days: 14
|
||||||
|
jellyfin_cache_max_age_days: 30
|
||||||
|
npm_cache_clean: false
|
||||||
|
apt_clean: true
|
||||||
|
disk_warn_percent: 80
|
||||||
|
thin_pool_warn_percent: 85
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
- name: Restart docker
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: docker
|
||||||
|
state: restarted
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
---
|
||||||
|
- name: Disk usage before maintenance
|
||||||
|
ansible.builtin.shell: df -hT / | tail -1
|
||||||
|
register: disk_before
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Show disk before
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ inventory_hostname }} before: {{ disk_before.stdout }}"
|
||||||
|
|
||||||
|
- name: Vacuum systemd journal
|
||||||
|
ansible.builtin.command: "journalctl --vacuum-size={{ journal_max_size }}"
|
||||||
|
register: journal_vacuum
|
||||||
|
changed_when: "'Vacuuming done' in journal_vacuum.stdout"
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Clean apt cache
|
||||||
|
ansible.builtin.apt:
|
||||||
|
autoclean: true
|
||||||
|
autoremove: true
|
||||||
|
clean: true
|
||||||
|
when: apt_clean | bool
|
||||||
|
|
||||||
|
- name: Check if docker is available
|
||||||
|
ansible.builtin.command: docker info
|
||||||
|
register: docker_info
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
tags: [always, docker]
|
||||||
|
|
||||||
|
- name: Truncate oversized Docker container logs
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
set -o pipefail
|
||||||
|
find /var/lib/docker/containers -name '*-json.log' -size +{{ docker_log_truncate_threshold }} \
|
||||||
|
-exec truncate -s {{ docker_log_truncate_target }} {} \;
|
||||||
|
echo done
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: log_truncate
|
||||||
|
changed_when: log_truncate.stdout is search('done')
|
||||||
|
when: docker_info is defined and docker_info.rc == 0
|
||||||
|
|
||||||
|
- name: Prune stopped containers
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
docker container prune -f --filter until={{ docker_prune_stopped_containers_older_than }}
|
||||||
|
register: container_prune
|
||||||
|
changed_when: "'Total reclaimed space' in container_prune.stdout and '0B' not in container_prune.stdout.split('Total reclaimed space')[1].split('\n')[0]"
|
||||||
|
when: docker_info is defined and docker_info.rc == 0
|
||||||
|
|
||||||
|
- name: Prune dangling images
|
||||||
|
ansible.builtin.command: docker image prune -f
|
||||||
|
register: image_prune_dangling
|
||||||
|
changed_when: "'Total reclaimed space' in image_prune_dangling.stdout and '0B' not in image_prune_dangling.stdout.split('Total reclaimed space')[1].split('\n')[0]"
|
||||||
|
when:
|
||||||
|
- docker_info is defined
|
||||||
|
- docker_info.rc == 0
|
||||||
|
- docker_prune_dangling_images | bool
|
||||||
|
|
||||||
|
- name: Prune unused images older than threshold
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
docker image prune -af --filter until={{ docker_prune_unused_images_older_than }}
|
||||||
|
register: image_prune_old
|
||||||
|
changed_when: "'Total reclaimed space' in image_prune_old.stdout and '0B' not in image_prune_old.stdout.split('Total reclaimed space')[1].split('\n')[0]"
|
||||||
|
when:
|
||||||
|
- docker_info is defined
|
||||||
|
- docker_info.rc == 0
|
||||||
|
- docker_prune_unused_images_older_than | length > 0
|
||||||
|
tags:
|
||||||
|
- aggressive
|
||||||
|
|
||||||
|
- name: Prune docker build cache
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
docker builder prune -af --filter until={{ docker_prune_build_cache_older_than }}
|
||||||
|
register: builder_prune
|
||||||
|
changed_when: "'Total:' in builder_prune.stdout"
|
||||||
|
failed_when: false
|
||||||
|
when: docker_info is defined and docker_info.rc == 0
|
||||||
|
|
||||||
|
- name: Prune dangling docker volumes
|
||||||
|
ansible.builtin.command: docker volume prune -f
|
||||||
|
register: volume_prune
|
||||||
|
changed_when: "'Total reclaimed space' in volume_prune.stdout and '0B' not in volume_prune.stdout.split('Total reclaimed space')[1].split('\n')[0]"
|
||||||
|
when:
|
||||||
|
- docker_info is defined
|
||||||
|
- docker_info.rc == 0
|
||||||
|
- docker_prune_dangling_volumes | bool
|
||||||
|
|
||||||
|
- name: Check for existing Docker daemon.json
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /etc/docker/daemon.json
|
||||||
|
register: docker_daemon_json
|
||||||
|
when: docker_info is defined and docker_info.rc == 0
|
||||||
|
|
||||||
|
- name: Ensure Docker log rotation defaults
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/docker/daemon.json
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
force: false
|
||||||
|
content: |
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notify: Restart docker
|
||||||
|
when:
|
||||||
|
- docker_info is defined
|
||||||
|
- docker_info.rc == 0
|
||||||
|
- not docker_daemon_json.stat.exists
|
||||||
|
|
||||||
|
- name: Remove old Frigate recording day folders
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
set -euo pipefail
|
||||||
|
retain={{ frigate_recordings_retain_days }}
|
||||||
|
cutoff=$(date -d "-${retain} days" +%Y-%m-%d)
|
||||||
|
removed=0
|
||||||
|
for d in "{{ frigate_recordings_path }}"/20??-??-??; do
|
||||||
|
[ -d "$d" ] || continue
|
||||||
|
day=$(basename "$d")
|
||||||
|
if [[ "$day" < "$cutoff" ]]; then
|
||||||
|
rm -rf "$d"
|
||||||
|
echo "removed $day"
|
||||||
|
removed=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ "$removed" -eq 0 ] || true
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: frigate_recording_cleanup
|
||||||
|
changed_when: frigate_recording_cleanup.stdout | length > 0
|
||||||
|
when:
|
||||||
|
- frigate_recordings_path is defined
|
||||||
|
- frigate_recordings_path | length > 0
|
||||||
|
tags:
|
||||||
|
- frigate
|
||||||
|
|
||||||
|
- name: Remove old Frigate clip previews
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: "{{ frigate_clips_path | default('') }}/previews"
|
||||||
|
age: "{{ frigate_clips_retain_days }}d"
|
||||||
|
file_type: any
|
||||||
|
recurse: true
|
||||||
|
register: old_frigate_clips
|
||||||
|
when:
|
||||||
|
- frigate_clips_path is defined
|
||||||
|
- frigate_clips_path | length > 0
|
||||||
|
|
||||||
|
- name: Delete old Frigate clip files
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item.path }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ old_frigate_clips.files | default([]) }}"
|
||||||
|
when:
|
||||||
|
- frigate_clips_path is defined
|
||||||
|
- frigate_clips_path | length > 0
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.path }}"
|
||||||
|
tags:
|
||||||
|
- frigate
|
||||||
|
|
||||||
|
- name: Clean stale Jellyfin cache files
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: "{{ jellyfin_cache_path | default('') }}"
|
||||||
|
age: "{{ jellyfin_cache_max_age_days }}d"
|
||||||
|
file_type: file
|
||||||
|
recurse: true
|
||||||
|
register: old_jellyfin_cache
|
||||||
|
when:
|
||||||
|
- jellyfin_cache_path is defined
|
||||||
|
- jellyfin_cache_path | length > 0
|
||||||
|
|
||||||
|
- name: Delete stale Jellyfin cache
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item.path }}"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ old_jellyfin_cache.files | default([]) }}"
|
||||||
|
when:
|
||||||
|
- jellyfin_cache_path is defined
|
||||||
|
- jellyfin_cache_path | length > 0
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.path }}"
|
||||||
|
tags:
|
||||||
|
- jellyfin
|
||||||
|
|
||||||
|
- name: Clean npm cache on dev hosts
|
||||||
|
ansible.builtin.command: npm cache clean --force
|
||||||
|
when:
|
||||||
|
- dev_tooling_cleanup | default(false) | bool
|
||||||
|
- npm_cache_clean | bool
|
||||||
|
changed_when: true
|
||||||
|
failed_when: false
|
||||||
|
tags:
|
||||||
|
- dev-tooling
|
||||||
|
|
||||||
|
- name: Run fstrim on root filesystem
|
||||||
|
ansible.builtin.command: fstrim -v /
|
||||||
|
register: fstrim_result
|
||||||
|
changed_when: "'trimmed' in fstrim_result.stdout and '0 B' not in fstrim_result.stdout"
|
||||||
|
when: fstrim_enabled | bool
|
||||||
|
|
||||||
|
- name: Docker disk summary
|
||||||
|
ansible.builtin.command: docker system df
|
||||||
|
register: docker_df
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
when: docker_info is defined and docker_info.rc == 0
|
||||||
|
|
||||||
|
- name: Disk usage after maintenance
|
||||||
|
ansible.builtin.shell: df -hT / | tail -1
|
||||||
|
register: disk_after
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Maintenance summary
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: |
|
||||||
|
{{ inventory_hostname }}:
|
||||||
|
before: {{ disk_before.stdout }}
|
||||||
|
after: {{ disk_after.stdout }}
|
||||||
|
fstrim: {{ fstrim_result.stdout | default('skipped') }}
|
||||||
|
docker: {{ docker_df.stdout | default('n/a') }}
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Weekly disk maintenance — runs Ansible playbook from Proxmox host
|
||||||
|
set -euo pipefail
|
||||||
|
export ANSIBLE_CONFIG=/root/ansible/ansible.cfg
|
||||||
|
LOG=/var/log/pve-lxc-disk-maintenance.log
|
||||||
|
exec >>"$LOG" 2>&1
|
||||||
|
echo "=== $(date -Is) disk maintenance start ==="
|
||||||
|
ansible-playbook /root/ansible/playbooks/disk-maintenance.yml
|
||||||
|
echo "=== $(date -Is) disk maintenance done ==="
|
||||||
@@ -63,6 +63,16 @@ Pfad: `/usr/local/go/bin/go` — in `~/.bashrc`:
|
|||||||
export PATH="/usr/local/go/bin:$PATH"
|
export PATH="/usr/local/go/bin:$PATH"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Weitere Pfade in `docu`
|
||||||
|
|
||||||
|
| Pfad | Inhalt |
|
||||||
|
|------|--------|
|
||||||
|
| [shared/ssh/](ssh/README.md) | Gemeinsame `authorized_keys`-Fragmente + Deploy-Skript |
|
||||||
|
| `pve1/ansible/` | Fish-Setup für VM 101 |
|
||||||
|
| `pve2/ansible/` | LXC Disk-Maintenance (Cron auf pve2) |
|
||||||
|
|
||||||
|
Symlinks auf den Hosts: `ln -sfn /root/docu/pve{1,2}/ansible /root/ansible`
|
||||||
|
|
||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# SSH — gemeinsame authorized_keys
|
||||||
|
|
||||||
|
Zentraler Katalog **öffentlicher** SSH-Keys (keine Private Keys). Stand aus den Hosts exportiert — bei neuem Laptop Key in `fragments/` ergänzen, `rebuild-assembled.sh` laufen lassen.
|
||||||
|
|
||||||
|
## Struktur
|
||||||
|
|
||||||
|
```
|
||||||
|
shared/ssh/
|
||||||
|
├── fragments/ # Einzelne Key-Gruppen (editierbar)
|
||||||
|
├── assembled/ # Fertige Sets pro Ziel (generiert)
|
||||||
|
├── rebuild-assembled.sh # fragments → assembled
|
||||||
|
└── install-authorized-keys.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
| Fragment | Inhalt |
|
||||||
|
|----------|--------|
|
||||||
|
| [fragments/admin-workstations.pub](fragments/admin-workstations.pub) | DESKTOP-H9797I1, DESKTOP-J08NPU2 |
|
||||||
|
| [fragments/admin-laptops-extra.pub](fragments/admin-laptops-extra.pub) | L7L1S5V, OJIEMRE, x380, Security Keys |
|
||||||
|
| [fragments/admin-mobile.pub](fragments/admin-mobile.pub) | JuiceSSH, server6, WEBTOP |
|
||||||
|
| [fragments/host-pve1.pub](fragments/host-pve1.pub) | root@pve1 ed25519 |
|
||||||
|
| [fragments/host-pve2.pub](fragments/host-pve2.pub) | root@pve2 (Ansible / Host-SSH) |
|
||||||
|
| [fragments/legacy-pve1-rsa.pub](fragments/legacy-pve1-rsa.pub) | Altes RSA auf pve1 (Kommentar „root@pve2“) |
|
||||||
|
|
||||||
|
## Assembled Sets → Ziel
|
||||||
|
|
||||||
|
| Datei | Deploy auf | User |
|
||||||
|
|-------|------------|------|
|
||||||
|
| [assembled/proxmox-root.pub](assembled/proxmox-root.pub) | pve1 `192.168.10.5`, pve2 `192.168.10.4` | root |
|
||||||
|
| [assembled/vm101-jean.pub](assembled/vm101-jean.pub) | VM 101 Ubuntu `192.168.10.10` | jean |
|
||||||
|
| [assembled/pve2-lxc-root.pub](assembled/pve2-lxc-root.pub) | CT 101 docker, 109 media, 110 AIDEV (pve2) | root |
|
||||||
|
| [assembled/authorized_keys.all.pub](assembled/authorized_keys.all.pub) | Referenz — alle Keys vereint | — |
|
||||||
|
|
||||||
|
### Matrix (Ist-Zustand)
|
||||||
|
|
||||||
|
| Host | Empfohlenes Set | Anmerkung |
|
||||||
|
|------|-----------------|-----------|
|
||||||
|
| root@pve1 | proxmox-root | + legacy RSA noch enthalten |
|
||||||
|
| root@pve2 | proxmox-root | ohne legacy RSA (reicht host-pve2) |
|
||||||
|
| jean@192.168.10.10 | vm101-jean | Ansible fish-setup nutzt jean + SSH |
|
||||||
|
| CT 101 (docker) | pve2-lxc-root | Ansible disk-maintenance |
|
||||||
|
| CT 109 (media) | subset: admin + OJIEMRE | aktuell nur OJIEMRE — bei Bedarf volles Set |
|
||||||
|
| CT 110 (aidev) | pve2-lxc-root | **aktuell leer** — Keys fehlen für Ansible |
|
||||||
|
|
||||||
|
## Neuen Key hinzufügen
|
||||||
|
|
||||||
|
1. Passendes Fragment in `fragments/*.pub` editieren (eine Zeile pro Key)
|
||||||
|
2. `./rebuild-assembled.sh`
|
||||||
|
3. `./install-authorized-keys.sh <target>` oder manuell `cat assembled/….pub >> ~/.ssh/authorized_keys`
|
||||||
|
|
||||||
|
## Deploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /root/docu/shared/ssh
|
||||||
|
|
||||||
|
# Proxmox lokal
|
||||||
|
./install-authorized-keys.sh proxmox-root
|
||||||
|
|
||||||
|
# Remote
|
||||||
|
./install-authorized-keys.sh --remote root@192.168.10.4 proxmox-root
|
||||||
|
|
||||||
|
# VM 101
|
||||||
|
./install-authorized-keys.sh vm101-jean
|
||||||
|
|
||||||
|
# CTs auf pve2 (muss auf pve2 laufen)
|
||||||
|
./install-authorized-keys.sh pve2-lxc-root
|
||||||
|
./install-authorized-keys.sh pve2-lxc-root --ct 101
|
||||||
|
|
||||||
|
# Vorschau
|
||||||
|
./install-authorized-keys.sh --dry-run proxmox-root
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ansible
|
||||||
|
|
||||||
|
| Host | Ansible-Pfad | Keys |
|
||||||
|
|------|--------------|------|
|
||||||
|
| pve1 | [pve1/ansible/](../../pve1/ansible/) | jean → VM 101 |
|
||||||
|
| pve2 | [pve2/ansible/](../../pve2/ansible/) | root@pve2 → CTs |
|
||||||
|
|
||||||
|
Symlink auf dem Host: `ln -sfn /root/docu/pve{1,2}/ansible /root/ansible`
|
||||||
|
|
||||||
|
## Hinweise
|
||||||
|
|
||||||
|
- **Nur Public Keys** ins Repo — niemals `id_*` ohne `.pub` oder `.git-credentials-*`
|
||||||
|
- Zwei verschiedene `ssh-rsa … root@pve2`: aktueller Key auf pve2 vs. Legacy auf pve1 (`legacy-pve1-rsa.pub`)
|
||||||
|
- CT 110: vor Ansible-Wartung Keys deployen (`pve2-lxc-root`)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAj1SFdqGjsIrF644ywWANqDMrsrlSBAQiM1HWEfwOIF jean@DESKTOP-L7L1S5V
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII8YFIl6gZ6taPAoDPJtkwkcfEpas9MbVgdkuQuBOJvh jean@DESKTOP-OJIEMRE
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID/3NRXevRiFpmLGkrZTA1Fp2FigYtDvvpG8Ta60U28p jean@x380
|
||||||
|
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEohWH3Rqh0+h5sYmi921rf3l2mZ0RXebCS8hR9pmHIiAAAABHNzaDo= jean@DESKTOP-DA5D3IG
|
||||||
|
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEGR43JnbBQNZ3U9onHM1XoFiJStBUmGTf2yr9p/haYuAAAABHNzaDo= jean@DESKTOP-2N4HRBF
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIY8YOBNfgjm9AVLycI0V5So2FZFjSk5BTH/K+SLajnw JuiceSSH
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCTs4xGQ9bW9eB3gfPx10Ddi7rxqnYFM+BFT7+DuUeoIiKtOGQLJWO+4ShJt6uNbD1Sk/VRtHxC2zF5h0oe4ZrDLOpVwwD+3e9IkFmtUXcTdVOfL0SDfjeZ8EeW25pTz10pXuwckiKoGGh42a1giATPf9jT63p9qa+hM51DpMMbZPN3k2ZJLzjpwhA4n2xcBbcFGkj3Brp6Tsn3x2T/kDwwuaOAfD8elAwM+etnDE8RhztdFXmWWJqxkTane6nInp0JPeKe/Uq/MEGDNiOhGH5BUC8FFNJQiHF9JspHitL2zbmT7zev29VWJgzMFrD2avn7gVyo9T7VnRF0gxh2ZzeRuDob9tHYYXCg8UG9q4V7uDJBEWoidCKAzn44DDWA4zeBfbwKdh1Muff6LNGwoRtyKgpTf5VsA+zjw/SkKS9xASJZKD4IN11Q1bN4BHhLkwfB0bKFIfDyQlCf+IVb64+uQhICe9qwZPG6SLl0ok2DU3CbL3wdLsQWTrdiOPXtPT0= jean@server6
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJSVmBVrCmUuCgKS4L3w6jRq2Efi/28ghElDSs22Hu2G abc@bdad197f6631
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOfSnbZKfHpVI9w8ogdfsA7XnYA28goelOfq+w3X02Bx jean@DESKTOP-H9797I1
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0ToemBZ+/ibr9k0LHsn2J0JuLalXw//TLmC0ydE7vr jean@DESKTOP-J08NPU2
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJJvDmBpuduGeVdN92I/tr5YkfmQo5fQ4lI5ZgakRQef root@pve1
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICXDMnLAJlxd56f6BCJAjVFbaTDcI2lLMOQf1OWCGzaA root@pve2
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC6NPVyFfE1hUimqs18TxjIB72+o59CVVQbJzK0cGmvzROnoR4iGPelwvGFnRUOdUbnGXK5TkQQB6dCnLKHEdULyQ5yXimI37Ywerr5cMorUF3QtWp4WHs2ewPgvdjc0gL0GLlSq7mHQ649PZbhpHo8GlOudsdEVqoxOKcvI/V572huuItTYj0AMnSHglQ1NR0jjeo6ItDblEpU6Anj4knqQYYyOD1CGAJZaKt+2UXsIV3xhkDFhq6Xv83VIj3T4Cju9VsIqFb5eOUUu7er0WpF0rqEqcVliPlq4Ja+eJ1Wl9HnD/5tUeM5yWDHynXTwSlMUCVvnaBtrFbIFhDR9pxWGEnNy6UEjiLRIrYkNMKr+QnzTesB8N8jvfPJoAMcESZAAi675PawbqYxK59ZG+sa/sX83G7GFl5MtB0lUhiyCJPdGUa63QfQw0J8X0dvkZCNcpsDWhbq9B+uu1GL1JS2Rr2uoYSwfIFUiyaQY8KniYlzYb2TyImEQZ7UYkTurIYVutjGJwNqr5KhrZb6flkt/t7fHe/rAScbhm/4lVQFYZYGggitnR6rh262CBl2ML53V1crhLzPjOQWu770y64mZBjf+NwWK84ikPsA0ei2/ph+oWnAkYZVbWVR47AOnLqDed95jJBL5rbAkeSe32MDTPG638pfiBRl/mvPdabZcQ== root@pve2
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvZFYXzxAFFa6aDpAOE/SlhU6yDYTxcP3h1NUyZvW2z/pXg05bQ1ZclYwk3RWjBRj4LQeYqClGyiXDo3bTJFusFq+UWVoYr0OIzyEu+5o+rNavErJxXRyiCFb61sSpxwanlec4MqTTNv8SvRHmmZPUjnfHRKjbHbj4LxMZT4cu3PSYAH98ANdgYw5ufZWuCQHxKN9LvQ8K/1JQAbxOGisnovIMtYo96NBk49FWHHQ29O0A5qDMW8HU9jXfWq5GTYplRdr7pnWDJBjuAUudmtG9vcMGZep5ExA2v9nfsbji4jemntBViDwk3mKcYn5NwIWrot89CON5Qe62QRSJnja5c7fSEPs+I2ltJ3ExLWwIMrQQua+yNJlGSkjLw8y1McuSUIk1FNRxLh4S1TDJOZ4zgHwHQFn1CV3+ZCCD0IM0VNKFpOgNmdQoziHIz96dCeZaQRFXl1Cf0YfhRwhuUqI8ifhgy32GfC5HlR82KRWYFNofZymRCMWaN8jMjfZZ3K2RkiAQUfjc9iojzY0NSO9kbM8RorHXNMgNkQVozgE//baULBCAYqT0q9jHd8mdqf4cfZ+Oj/EDqlnX6YNk+AC6VGmp4LlqWZGRdM9ovXoDe9g82RPypJI8fF0Ie0ws9rOQoVEzCmG9d3EXIQXn5M6JF660QgfcUrKTwUW/mKs0eQ== root@pve2
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOfSnbZKfHpVI9w8ogdfsA7XnYA28goelOfq+w3X02Bx jean@DESKTOP-H9797I1
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0ToemBZ+/ibr9k0LHsn2J0JuLalXw//TLmC0ydE7vr jean@DESKTOP-J08NPU2
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJJvDmBpuduGeVdN92I/tr5YkfmQo5fQ4lI5ZgakRQef root@pve1
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICXDMnLAJlxd56f6BCJAjVFbaTDcI2lLMOQf1OWCGzaA root@pve2
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC6NPVyFfE1hUimqs18TxjIB72+o59CVVQbJzK0cGmvzROnoR4iGPelwvGFnRUOdUbnGXK5TkQQB6dCnLKHEdULyQ5yXimI37Ywerr5cMorUF3QtWp4WHs2ewPgvdjc0gL0GLlSq7mHQ649PZbhpHo8GlOudsdEVqoxOKcvI/V572huuItTYj0AMnSHglQ1NR0jjeo6ItDblEpU6Anj4knqQYYyOD1CGAJZaKt+2UXsIV3xhkDFhq6Xv83VIj3T4Cju9VsIqFb5eOUUu7er0WpF0rqEqcVliPlq4Ja+eJ1Wl9HnD/5tUeM5yWDHynXTwSlMUCVvnaBtrFbIFhDR9pxWGEnNy6UEjiLRIrYkNMKr+QnzTesB8N8jvfPJoAMcESZAAi675PawbqYxK59ZG+sa/sX83G7GFl5MtB0lUhiyCJPdGUa63QfQw0J8X0dvkZCNcpsDWhbq9B+uu1GL1JS2Rr2uoYSwfIFUiyaQY8KniYlzYb2TyImEQZ7UYkTurIYVutjGJwNqr5KhrZb6flkt/t7fHe/rAScbhm/4lVQFYZYGggitnR6rh262CBl2ML53V1crhLzPjOQWu770y64mZBjf+NwWK84ikPsA0ei2/ph+oWnAkYZVbWVR47AOnLqDed95jJBL5rbAkeSe32MDTPG638pfiBRl/mvPdabZcQ== root@pve2
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvZFYXzxAFFa6aDpAOE/SlhU6yDYTxcP3h1NUyZvW2z/pXg05bQ1ZclYwk3RWjBRj4LQeYqClGyiXDo3bTJFusFq+UWVoYr0OIzyEu+5o+rNavErJxXRyiCFb61sSpxwanlec4MqTTNv8SvRHmmZPUjnfHRKjbHbj4LxMZT4cu3PSYAH98ANdgYw5ufZWuCQHxKN9LvQ8K/1JQAbxOGisnovIMtYo96NBk49FWHHQ29O0A5qDMW8HU9jXfWq5GTYplRdr7pnWDJBjuAUudmtG9vcMGZep5ExA2v9nfsbji4jemntBViDwk3mKcYn5NwIWrot89CON5Qe62QRSJnja5c7fSEPs+I2ltJ3ExLWwIMrQQua+yNJlGSkjLw8y1McuSUIk1FNRxLh4S1TDJOZ4zgHwHQFn1CV3+ZCCD0IM0VNKFpOgNmdQoziHIz96dCeZaQRFXl1Cf0YfhRwhuUqI8ifhgy32GfC5HlR82KRWYFNofZymRCMWaN8jMjfZZ3K2RkiAQUfjc9iojzY0NSO9kbM8RorHXNMgNkQVozgE//baULBCAYqT0q9jHd8mdqf4cfZ+Oj/EDqlnX6YNk+AC6VGmp4LlqWZGRdM9ovXoDe9g82RPypJI8fF0Ie0ws9rOQoVEzCmG9d3EXIQXn5M6JF660QgfcUrKTwUW/mKs0eQ== root@pve2
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOfSnbZKfHpVI9w8ogdfsA7XnYA28goelOfq+w3X02Bx jean@DESKTOP-H9797I1
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0ToemBZ+/ibr9k0LHsn2J0JuLalXw//TLmC0ydE7vr jean@DESKTOP-J08NPU2
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICXDMnLAJlxd56f6BCJAjVFbaTDcI2lLMOQf1OWCGzaA root@pve2
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC6NPVyFfE1hUimqs18TxjIB72+o59CVVQbJzK0cGmvzROnoR4iGPelwvGFnRUOdUbnGXK5TkQQB6dCnLKHEdULyQ5yXimI37Ywerr5cMorUF3QtWp4WHs2ewPgvdjc0gL0GLlSq7mHQ649PZbhpHo8GlOudsdEVqoxOKcvI/V572huuItTYj0AMnSHglQ1NR0jjeo6ItDblEpU6Anj4knqQYYyOD1CGAJZaKt+2UXsIV3xhkDFhq6Xv83VIj3T4Cju9VsIqFb5eOUUu7er0WpF0rqEqcVliPlq4Ja+eJ1Wl9HnD/5tUeM5yWDHynXTwSlMUCVvnaBtrFbIFhDR9pxWGEnNy6UEjiLRIrYkNMKr+QnzTesB8N8jvfPJoAMcESZAAi675PawbqYxK59ZG+sa/sX83G7GFl5MtB0lUhiyCJPdGUa63QfQw0J8X0dvkZCNcpsDWhbq9B+uu1GL1JS2Rr2uoYSwfIFUiyaQY8KniYlzYb2TyImEQZ7UYkTurIYVutjGJwNqr5KhrZb6flkt/t7fHe/rAScbhm/4lVQFYZYGggitnR6rh262CBl2ML53V1crhLzPjOQWu770y64mZBjf+NwWK84ikPsA0ei2/ph+oWnAkYZVbWVR47AOnLqDed95jJBL5rbAkeSe32MDTPG638pfiBRl/mvPdabZcQ== root@pve2
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAj1SFdqGjsIrF644ywWANqDMrsrlSBAQiM1HWEfwOIF jean@DESKTOP-L7L1S5V
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII8YFIl6gZ6taPAoDPJtkwkcfEpas9MbVgdkuQuBOJvh jean@DESKTOP-OJIEMRE
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID/3NRXevRiFpmLGkrZTA1Fp2FigYtDvvpG8Ta60U28p jean@x380
|
||||||
|
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEohWH3Rqh0+h5sYmi921rf3l2mZ0RXebCS8hR9pmHIiAAAABHNzaDo= jean@DESKTOP-DA5D3IG
|
||||||
|
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEGR43JnbBQNZ3U9onHM1XoFiJStBUmGTf2yr9p/haYuAAAABHNzaDo= jean@DESKTOP-2N4HRBF
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIY8YOBNfgjm9AVLycI0V5So2FZFjSk5BTH/K+SLajnw JuiceSSH
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCTs4xGQ9bW9eB3gfPx10Ddi7rxqnYFM+BFT7+DuUeoIiKtOGQLJWO+4ShJt6uNbD1Sk/VRtHxC2zF5h0oe4ZrDLOpVwwD+3e9IkFmtUXcTdVOfL0SDfjeZ8EeW25pTz10pXuwckiKoGGh42a1giATPf9jT63p9qa+hM51DpMMbZPN3k2ZJLzjpwhA4n2xcBbcFGkj3Brp6Tsn3x2T/kDwwuaOAfD8elAwM+etnDE8RhztdFXmWWJqxkTane6nInp0JPeKe/Uq/MEGDNiOhGH5BUC8FFNJQiHF9JspHitL2zbmT7zev29VWJgzMFrD2avn7gVyo9T7VnRF0gxh2ZzeRuDob9tHYYXCg8UG9q4V7uDJBEWoidCKAzn44DDWA4zeBfbwKdh1Muff6LNGwoRtyKgpTf5VsA+zjw/SkKS9xASJZKD4IN11Q1bN4BHhLkwfB0bKFIfDyQlCf+IVb64+uQhICe9qwZPG6SLl0ok2DU3CbL3wdLsQWTrdiOPXtPT0= jean@server6
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJSVmBVrCmUuCgKS4L3w6jRq2Efi/28ghElDSs22Hu2G abc@bdad197f6631
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOfSnbZKfHpVI9w8ogdfsA7XnYA28goelOfq+w3X02Bx jean@DESKTOP-H9797I1
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0ToemBZ+/ibr9k0LHsn2J0JuLalXw//TLmC0ydE7vr jean@DESKTOP-J08NPU2
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAj1SFdqGjsIrF644ywWANqDMrsrlSBAQiM1HWEfwOIF jean@DESKTOP-L7L1S5V
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII8YFIl6gZ6taPAoDPJtkwkcfEpas9MbVgdkuQuBOJvh jean@DESKTOP-OJIEMRE
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID/3NRXevRiFpmLGkrZTA1Fp2FigYtDvvpG8Ta60U28p jean@x380
|
||||||
|
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEohWH3Rqh0+h5sYmi921rf3l2mZ0RXebCS8hR9pmHIiAAAABHNzaDo= jean@DESKTOP-DA5D3IG
|
||||||
|
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEGR43JnbBQNZ3U9onHM1XoFiJStBUmGTf2yr9p/haYuAAAABHNzaDo= jean@DESKTOP-2N4HRBF
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIY8YOBNfgjm9AVLycI0V5So2FZFjSk5BTH/K+SLajnw JuiceSSH
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCTs4xGQ9bW9eB3gfPx10Ddi7rxqnYFM+BFT7+DuUeoIiKtOGQLJWO+4ShJt6uNbD1Sk/VRtHxC2zF5h0oe4ZrDLOpVwwD+3e9IkFmtUXcTdVOfL0SDfjeZ8EeW25pTz10pXuwckiKoGGh42a1giATPf9jT63p9qa+hM51DpMMbZPN3k2ZJLzjpwhA4n2xcBbcFGkj3Brp6Tsn3x2T/kDwwuaOAfD8elAwM+etnDE8RhztdFXmWWJqxkTane6nInp0JPeKe/Uq/MEGDNiOhGH5BUC8FFNJQiHF9JspHitL2zbmT7zev29VWJgzMFrD2avn7gVyo9T7VnRF0gxh2ZzeRuDob9tHYYXCg8UG9q4V7uDJBEWoidCKAzn44DDWA4zeBfbwKdh1Muff6LNGwoRtyKgpTf5VsA+zjw/SkKS9xASJZKD4IN11Q1bN4BHhLkwfB0bKFIfDyQlCf+IVb64+uQhICe9qwZPG6SLl0ok2DU3CbL3wdLsQWTrdiOPXtPT0= jean@server6
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJSVmBVrCmUuCgKS4L3w6jRq2Efi/28ghElDSs22Hu2G abc@bdad197f6631
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJJvDmBpuduGeVdN92I/tr5YkfmQo5fQ4lI5ZgakRQef root@pve1
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Weitere Laptops / Geräte (VM 101, CTs)
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAj1SFdqGjsIrF644ywWANqDMrsrlSBAQiM1HWEfwOIF jean@DESKTOP-L7L1S5V
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII8YFIl6gZ6taPAoDPJtkwkcfEpas9MbVgdkuQuBOJvh jean@DESKTOP-OJIEMRE
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID/3NRXevRiFpmLGkrZTA1Fp2FigYtDvvpG8Ta60U28p jean@x380
|
||||||
|
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEohWH3Rqh0+h5sYmi921rf3l2mZ0RXebCS8hR9pmHIiAAAABHNzaDo= jean@DESKTOP-DA5D3IG
|
||||||
|
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEGR43JnbBQNZ3U9onHM1XoFiJStBUmGTf2yr9p/haYuAAAABHNzaDo= jean@DESKTOP-2N4HRBF
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Mobil / Sonstiges
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIY8YOBNfgjm9AVLycI0V5So2FZFjSk5BTH/K+SLajnw JuiceSSH
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCTs4xGQ9bW9eB3gfPx10Ddi7rxqnYFM+BFT7+DuUeoIiKtOGQLJWO+4ShJt6uNbD1Sk/VRtHxC2zF5h0oe4ZrDLOpVwwD+3e9IkFmtUXcTdVOfL0SDfjeZ8EeW25pTz10pXuwckiKoGGh42a1giATPf9jT63p9qa+hM51DpMMbZPN3k2ZJLzjpwhA4n2xcBbcFGkj3Brp6Tsn3x2T/kDwwuaOAfD8elAwM+etnDE8RhztdFXmWWJqxkTane6nInp0JPeKe/Uq/MEGDNiOhGH5BUC8FFNJQiHF9JspHitL2zbmT7zev29VWJgzMFrD2avn7gVyo9T7VnRF0gxh2ZzeRuDob9tHYYXCg8UG9q4V7uDJBEWoidCKAzn44DDWA4zeBfbwKdh1Muff6LNGwoRtyKgpTf5VsA+zjw/SkKS9xASJZKD4IN11Q1bN4BHhLkwfB0bKFIfDyQlCf+IVb64+uQhICe9qwZPG6SLl0ok2DU3CbL3wdLsQWTrdiOPXtPT0= jean@server6
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJSVmBVrCmUuCgKS4L3w6jRq2Efi/28ghElDSs22Hu2G abc@bdad197f6631
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Jean — Desktop/Laptop (Hauptzugang Proxmox)
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOfSnbZKfHpVI9w8ogdfsA7XnYA28goelOfq+w3X02Bx jean@DESKTOP-H9797I1
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0ToemBZ+/ibr9k0LHsn2J0JuLalXw//TLmC0ydE7vr jean@DESKTOP-J08NPU2
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Host-Key pve1 (192.168.10.5) — für SSH von pve2 → pve1
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJJvDmBpuduGeVdN92I/tr5YkfmQo5fQ4lI5ZgakRQef root@pve1
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Host-Keys pve2 (192.168.10.4) — Ansible + Host-zu-Host
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICXDMnLAJlxd56f6BCJAjVFbaTDcI2lLMOQf1OWCGzaA root@pve2
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC6NPVyFfE1hUimqs18TxjIB72+o59CVVQbJzK0cGmvzROnoR4iGPelwvGFnRUOdUbnGXK5TkQQB6dCnLKHEdULyQ5yXimI37Ywerr5cMorUF3QtWp4WHs2ewPgvdjc0gL0GLlSq7mHQ649PZbhpHo8GlOudsdEVqoxOKcvI/V572huuItTYj0AMnSHglQ1NR0jjeo6ItDblEpU6Anj4knqQYYyOD1CGAJZaKt+2UXsIV3xhkDFhq6Xv83VIj3T4Cju9VsIqFb5eOUUu7er0WpF0rqEqcVliPlq4Ja+eJ1Wl9HnD/5tUeM5yWDHynXTwSlMUCVvnaBtrFbIFhDR9pxWGEnNy6UEjiLRIrYkNMKr+QnzTesB8N8jvfPJoAMcESZAAi675PawbqYxK59ZG+sa/sX83G7GFl5MtB0lUhiyCJPdGUa63QfQw0J8X0dvkZCNcpsDWhbq9B+uu1GL1JS2Rr2uoYSwfIFUiyaQY8KniYlzYb2TyImEQZ7UYkTurIYVutjGJwNqr5KhrZb6flkt/t7fHe/rAScbhm/4lVQFYZYGggitnR6rh262CBl2ML53V1crhLzPjOQWu770y64mZBjf+NwWK84ikPsA0ei2/ph+oWnAkYZVbWVR47AOnLqDed95jJBL5rbAkeSe32MDTPG638pfiBRl/mvPdabZcQ== root@pve2
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Legacy: RSA auf pve1, Kommentar irreführend „root@pve2“ — steht noch auf pve1 authorized_keys
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvZFYXzxAFFa6aDpAOE/SlhU6yDYTxcP3h1NUyZvW2z/pXg05bQ1ZclYwk3RWjBRj4LQeYqClGyiXDo3bTJFusFq+UWVoYr0OIzyEu+5o+rNavErJxXRyiCFb61sSpxwanlec4MqTTNv8SvRHmmZPUjnfHRKjbHbj4LxMZT4cu3PSYAH98ANdgYw5ufZWuCQHxKN9LvQ8K/1JQAbxOGisnovIMtYo96NBk49FWHHQ29O0A5qDMW8HU9jXfWq5GTYplRdr7pnWDJBjuAUudmtG9vcMGZep5ExA2v9nfsbji4jemntBViDwk3mKcYn5NwIWrot89CON5Qe62QRSJnja5c7fSEPs+I2ltJ3ExLWwIMrQQua+yNJlGSkjLw8y1McuSUIk1FNRxLh4S1TDJOZ4zgHwHQFn1CV3+ZCCD0IM0VNKFpOgNmdQoziHIz96dCeZaQRFXl1Cf0YfhRwhuUqI8ifhgy32GfC5HlR82KRWYFNofZymRCMWaN8jMjfZZ3K2RkiAQUfjc9iojzY0NSO9kbM8RorHXNMgNkQVozgE//baULBCAYqT0q9jHd8mdqf4cfZ+Oj/EDqlnX6YNk+AC6VGmp4LlqWZGRdM9ovXoDe9g82RPypJI8fF0Ie0ws9rOQoVEzCmG9d3EXIQXn5M6JF660QgfcUrKTwUW/mKs0eQ== root@pve2
|
||||||
Executable
+131
@@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# authorized_keys aus docu/shared/ssh deployen
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DOCU_ROOT="${DOCU_ROOT:-/root/docu}"
|
||||||
|
SSH_DIR="$DOCU_ROOT/shared/ssh"
|
||||||
|
DRY_RUN=0
|
||||||
|
TARGET=""
|
||||||
|
DEST=""
|
||||||
|
REMOTE=""
|
||||||
|
CT_IDS=()
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: install-authorized-keys.sh [options] <target>
|
||||||
|
|
||||||
|
Targets:
|
||||||
|
proxmox-root → /root/.ssh/authorized_keys auf Proxmox-Hosts
|
||||||
|
vm101-jean → jean@192.168.10.10 ~/.ssh/authorized_keys
|
||||||
|
pve2-lxc-root → root in CTs auf pve2 (101 docker, 109 media, 110 aidev)
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--dest PATH Lokale Zieldatei (nur proxmox-root, default: /root/.ssh/authorized_keys)
|
||||||
|
--remote USER@HOST Auf Remote-Host installieren (proxmox-root / vm101-jean)
|
||||||
|
--ct VMID Nur einen CT (pve2-lxc-root, mehrfach möglich)
|
||||||
|
--dry-run Nur anzeigen, nicht schreiben
|
||||||
|
-h Hilfe
|
||||||
|
|
||||||
|
Beispiele:
|
||||||
|
./install-authorized-keys.sh proxmox-root
|
||||||
|
./install-authorized-keys.sh --remote root@192.168.10.5 proxmox-root
|
||||||
|
./install-authorized-keys.sh vm101-jean
|
||||||
|
./install-authorized-keys.sh pve2-lxc-root --ct 101
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
log() { printf '%s\n' "$*"; }
|
||||||
|
|
||||||
|
run() {
|
||||||
|
if (( DRY_RUN )); then
|
||||||
|
log "[dry-run] $*"
|
||||||
|
else
|
||||||
|
"$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_local_file() {
|
||||||
|
local src="$1" dest="$2"
|
||||||
|
run mkdir -p "$(dirname "$dest")"
|
||||||
|
run chmod 700 "$(dirname "$dest")"
|
||||||
|
if (( DRY_RUN )); then
|
||||||
|
log "[dry-run] cp $src → $dest"
|
||||||
|
head -3 "$src"
|
||||||
|
log "… ($(wc -l <"$src") Zeilen)"
|
||||||
|
else
|
||||||
|
install -m 600 -o root -g root "$src" "$dest"
|
||||||
|
log "Installiert: $dest ($(wc -l <"$dest") Keys)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_remote() {
|
||||||
|
local src="$1" remote="$2" dest="$3"
|
||||||
|
if (( DRY_RUN )); then
|
||||||
|
log "[dry-run] ssh $remote install -m 600 … ← $src"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
ssh "$remote" "mkdir -p $(dirname "$dest") && chmod 700 $(dirname "$dest")"
|
||||||
|
scp -q "$src" "$remote:/tmp/authorized_keys.new"
|
||||||
|
ssh "$remote" "install -m 600 -o \$(id -un) -g \$(id -gn) /tmp/authorized_keys.new '$dest' && rm -f /tmp/authorized_keys.new"
|
||||||
|
log "Installiert auf $remote:$dest"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_pve2_ct() {
|
||||||
|
local src="$1" vmid="$2"
|
||||||
|
if (( DRY_RUN )); then
|
||||||
|
log "[dry-run] pct exec $vmid → /root/.ssh/authorized_keys"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
pct exec "$vmid" -- mkdir -p /root/.ssh
|
||||||
|
pct exec "$vmid" -- chmod 700 /root/.ssh
|
||||||
|
pct push "$vmid" "$src" /root/.ssh/authorized_keys
|
||||||
|
pct exec "$vmid" -- chmod 600 /root/.ssh/authorized_keys
|
||||||
|
log "CT $vmid: /root/.ssh/authorized_keys ($(wc -l <"$src") Keys)"
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dest) DEST="$2"; shift 2 ;;
|
||||||
|
--remote) REMOTE="$2"; shift 2 ;;
|
||||||
|
--ct) CT_IDS+=("$2"); shift 2 ;;
|
||||||
|
--dry-run) DRY_RUN=1; shift ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
-*) echo "Unbekannte Option: $1" >&2; usage >&2; exit 1 ;;
|
||||||
|
*) TARGET="$1"; shift ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -n "$TARGET" ]] || { usage >&2; exit 1; }
|
||||||
|
[[ -d "$SSH_DIR/assembled" ]] || { echo "Fehlt: $SSH_DIR (git pull?)" >&2; exit 1; }
|
||||||
|
|
||||||
|
case "$TARGET" in
|
||||||
|
proxmox-root)
|
||||||
|
SRC="$SSH_DIR/assembled/proxmox-root.pub"
|
||||||
|
DEST="${DEST:-/root/.ssh/authorized_keys}"
|
||||||
|
if [[ -n "$REMOTE" ]]; then
|
||||||
|
install_remote "$SRC" "$REMOTE" "$DEST"
|
||||||
|
else
|
||||||
|
install_local_file "$SRC" "$DEST"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
vm101-jean)
|
||||||
|
SRC="$SSH_DIR/assembled/vm101-jean.pub"
|
||||||
|
DEST="${DEST:-/home/jean/.ssh/authorized_keys}"
|
||||||
|
REMOTE="${REMOTE:-jean@192.168.10.10}"
|
||||||
|
install_remote "$SRC" "$REMOTE" "$DEST"
|
||||||
|
;;
|
||||||
|
pve2-lxc-root)
|
||||||
|
SRC="$SSH_DIR/assembled/pve2-lxc-root.pub"
|
||||||
|
if [[ ${#CT_IDS[@]} -eq 0 ]]; then
|
||||||
|
CT_IDS=(101 109 110)
|
||||||
|
fi
|
||||||
|
for vmid in "${CT_IDS[@]}"; do
|
||||||
|
install_pve2_ct "$SRC" "$vmid"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unbekanntes Target: $TARGET" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Executable
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Regeneriert assembled/*.pub aus fragments/ (Dedupe nach Key-Material, Feld 2)
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
FRAG="$ROOT/fragments"
|
||||||
|
ASM="$ROOT/assembled"
|
||||||
|
|
||||||
|
dedupe() { awk '!seen[$2]++'; }
|
||||||
|
|
||||||
|
mkdir -p "$ASM"
|
||||||
|
|
||||||
|
build() {
|
||||||
|
local out="$1"; shift
|
||||||
|
{ for f in "$@"; do cat "$f"; done; } | grep -v '^#' | grep -v '^$' | dedupe > "$ASM/$out"
|
||||||
|
}
|
||||||
|
|
||||||
|
build proxmox-root.pub \
|
||||||
|
"$FRAG/admin-workstations.pub" \
|
||||||
|
"$FRAG/host-pve1.pub" \
|
||||||
|
"$FRAG/host-pve2.pub" \
|
||||||
|
"$FRAG/legacy-pve1-rsa.pub"
|
||||||
|
|
||||||
|
build vm101-jean.pub \
|
||||||
|
"$FRAG/admin-workstations.pub" \
|
||||||
|
"$FRAG/admin-laptops-extra.pub" \
|
||||||
|
"$FRAG/admin-mobile.pub" \
|
||||||
|
"$FRAG/host-pve1.pub"
|
||||||
|
|
||||||
|
build pve2-lxc-root.pub \
|
||||||
|
"$FRAG/admin-workstations.pub" \
|
||||||
|
"$FRAG/host-pve2.pub" \
|
||||||
|
"$FRAG/admin-laptops-extra.pub" \
|
||||||
|
"$FRAG/admin-mobile.pub"
|
||||||
|
|
||||||
|
build authorized_keys.all.pub \
|
||||||
|
"$FRAG"/*.pub
|
||||||
|
|
||||||
|
echo "OK: $(wc -l "$ASM"/*.pub | tail -1)"
|
||||||
Reference in New Issue
Block a user