Files
homelab-optimized/ansible/playbooks/portainer_stack_management.yml
Gitea Mirror Bot 57b1fe47f2
Some checks failed
Documentation / Deploy to GitHub Pages (push) Has been cancelled
Documentation / Build Docusaurus (push) Has been cancelled
Sanitized mirror from private repository - 2026-04-19 08:15:48 UTC
2026-04-19 08:15:48 +00:00

174 lines
5.4 KiB
YAML

---
# Portainer Stack Management via API
# Manages GitOps stacks across all Portainer endpoints
# Run with: ansible-playbook -i hosts.ini playbooks/portainer_stack_management.yml
- name: Portainer Stack Management
hosts: localhost
gather_facts: no
vars:
portainer_url: "https://192.168.0.200:9443"
portainer_username: "admin"
# portainer_password: "{{ vault_portainer_password }}" # Use ansible-vault
git_repo_url: "https://git.vish.gg/Vish/homelab.git"
# Portainer endpoints mapping
endpoints:
atlantis:
id: 1
name: "Atlantis"
stacks_path: "Atlantis"
calypso:
id: 2
name: "Calypso"
stacks_path: "Calypso"
concord_nuc:
id: 3
name: "Concord NUC"
stacks_path: "concord_nuc"
homelab_vm:
id: 4
name: "Homelab VM"
stacks_path: "homelab_vm"
rpi5:
id: 5
name: "RPi 5"
stacks_path: "raspberry-pi-5-vish"
tasks:
- name: Authenticate with Portainer
uri:
url: "{{ portainer_url }}/api/auth"
method: POST
body_format: json
body:
Username: "{{ portainer_username }}"
Password: "{{ portainer_password | default('admin') }}"
validate_certs: no
register: auth_response
no_log: true
- name: Set authentication token
set_fact:
portainer_token: "{{ auth_response.json.jwt }}"
- name: Get all endpoints
uri:
url: "{{ portainer_url }}/api/endpoints"
method: GET
headers:
Authorization: "Bearer {{ portainer_token }}"
validate_certs: no
register: endpoints_response
- name: Display available endpoints
debug:
msg: |
Available Portainer Endpoints:
{% for endpoint in endpoints_response.json %}
- ID: {{ endpoint.Id }}, Name: {{ endpoint.Name }}, Status: {{ endpoint.Status }}
{% endfor %}
- name: Get stacks for each endpoint
uri:
url: "{{ portainer_url }}/api/stacks"
method: GET
headers:
Authorization: "Bearer {{ portainer_token }}"
validate_certs: no
register: stacks_response
- name: Analyze GitOps stacks
set_fact:
gitops_stacks: "{{ stacks_response.json | selectattr('GitConfig', 'defined') | list }}"
non_gitops_stacks: "{{ stacks_response.json | rejectattr('GitConfig', 'defined') | list }}"
- name: Display GitOps status
debug:
msg: |
GitOps Stack Analysis:
- Total Stacks: {{ stacks_response.json | length }}
- GitOps Managed: {{ gitops_stacks | length }}
- Non-GitOps: {{ non_gitops_stacks | length }}
GitOps Stacks:
{% for stack in gitops_stacks %}
- {{ stack.Name }} (Endpoint: {{ stack.EndpointId }})
{% endfor %}
Non-GitOps Stacks:
{% for stack in non_gitops_stacks %}
- {{ stack.Name }} (Endpoint: {{ stack.EndpointId }})
{% endfor %}
- name: Check stack health
uri:
url: "{{ portainer_url }}/api/stacks/{{ item.Id }}/file"
method: GET
headers:
Authorization: "Bearer {{ portainer_token }}"
validate_certs: no
register: stack_files
loop: "{{ gitops_stacks }}"
failed_when: false
- name: Trigger GitOps sync for all stacks
uri:
url: "{{ portainer_url }}/api/stacks/{{ item.Id }}/git/redeploy"
method: PUT
headers:
Authorization: "Bearer {{ portainer_token }}"
body_format: json
body:
RepositoryReferenceName: "refs/heads/main"
PullImage: true
validate_certs: no
register: sync_results
loop: "{{ gitops_stacks }}"
when: sync_stacks | default(false) | bool
failed_when: false
- name: Display sync results
debug:
msg: |
GitOps Sync Results:
{% for result in sync_results.results %}
{% if result.skipped is not defined %}
- Stack: {{ gitops_stacks[loop.index0].Name }} - Status: {{ result.status | default('Failed') }}
{% endif %}
{% endfor %}
when: sync_stacks | default(false) | bool
- name: Generate stack health report
copy:
content: |
# Portainer Stack Health Report
Generated: {{ ansible_date_time.iso8601 }}
## Summary
- Total Stacks: {{ stacks_response.json | length }}
- GitOps Managed: {{ gitops_stacks | length }}
- Non-GitOps: {{ non_gitops_stacks | length }}
## GitOps Stacks
{% for stack in gitops_stacks %}
### {{ stack.Name }}
- Endpoint: {{ stack.EndpointId }}
- Status: {{ stack.Status }}
- Git Repository: {{ stack.GitConfig.URL if stack.GitConfig is defined else 'N/A' }}
- Git Reference: {{ stack.GitConfig.ReferenceName if stack.GitConfig is defined else 'N/A' }}
- Last Update: {{ stack.UpdatedAt }}
{% endfor %}
## Non-GitOps Stacks (Manual Management Required)
{% for stack in non_gitops_stacks %}
- {{ stack.Name }} (Endpoint: {{ stack.EndpointId }})
{% endfor %}
dest: "/tmp/portainer_stack_report_{{ ansible_date_time.epoch }}.md"
delegate_to: localhost
- name: Display report location
debug:
msg: "Stack health report saved to: /tmp/portainer_stack_report_{{ ansible_date_time.epoch }}.md"