Sanitized mirror from private repository - 2026-04-18 11:19:59 UTC
This commit is contained in:
173
ansible/playbooks/portainer_stack_management.yml
Normal file
173
ansible/playbooks/portainer_stack_management.yml
Normal file
@@ -0,0 +1,173 @@
|
||||
---
|
||||
# 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"
|
||||
Reference in New Issue
Block a user