feat: Auto deploy stacks on komodo (no storage yet)

This commit is contained in:
Lino Silva
2026-04-10 15:27:40 +01:00
parent 82b8bb2e2a
commit c3ecd9449e
7 changed files with 326 additions and 47 deletions
+1 -1
View File
@@ -242,4 +242,4 @@ komodo_db_password: "{{ vault_komodo_db_password }}"
komodo_webhook_secret: "{{ vault_komodo_webhook_secret }}"
komodo_jwt_secret: "{{ vault_komodo_jwt_secret }}"
komodo_onboarding_key: "{{ vault_komodo_onboarding_key }}"
komodo_core_address: "10.0.4.10:9120"
komodo_core_host: "10.0.4.10:9120"
+52 -45
View File
@@ -1,46 +1,53 @@
$ANSIBLE_VAULT;1.1;AES256
34633839643463656436373363623239343634393834353863336665613863663464316636343564
6561613766613735303865363339326563363961343739370a626535346366366261666131653565
39653832326235353662656466626132383531613338653138363039633563313536313765333166
6265343938386332340a313230353564653739633939363031623130316265373538333237343133
39303831303230323738383565303335363763353462353966643832626131646436336434323138
66636635326634383137376431323736613434656533633664383161393338326565336130303930
31303232393332623839323162373239616634356434643364323933613335363861343738313661
63306435303962323566346564383066636634663536646264383961343461623236386362336239
36316536346533626438366430363664383135346337303239643335656261626639323433313765
33613564626235323337343164346235336663613238323966346331623266613832633234393232
39393565383235373365353538373764333433386439333132643064373839643963376333373032
34613361663630323937333162373534356263373861363163303062363232663731316164653966
39346163353635663738316262363465643639313766346339333963333964336265303666643064
62643366613034663838326436313739363863316666393238306564306539623162636266393033
39653438663938346233656630366130316161373363393561663631663737373131383736666136
66346231663338643735313739343361643431396638613837303833616539373261346163306132
39656436626635633733396138303963343135343437313637346565643835613739653839343938
61623561303930306335383963393561393735316331323639373536616236383532366136653134
63366661363332366338656234386139363066363239656136383634623430303262626465356536
34303862303763613761616134323236316232373931386336653034633230396633363965313331
31666234363064323331666535316134623461663433366538613133396633353161323766363437
66396439303235313137393135383837323737663731386331376362613964323737366633623733
31353261306163356333303333393466643338343765323637656565333762386133363031396638
34386639393133303134383034316439363262386461346534326236326135623964363461646430
33623433306130393232353135623332396136653230383439333665303737343137383864356433
37313262383961656133393731656162316433356336336530333862363561353238663433343131
32353862363863343666383766363135663736613332313438356366303332326632653961313762
34363230633461616461373536366239313962616565396566316139393466303332643265353835
35356364343734663963303839363733393730633262643438336562643733623966663130353635
38363833633936363164313239323265623332643539356532623636383232323538386431653165
31353138666537616565646239303165376439373063356663316664356564323961613039663061
62336261306532386136616465383265613262363936633164373236353238633463303939623133
65313335653935346364383232373261666334663634373938353861383561613936393339366530
34303961373561303031323834663466346436383966373530633430333536373833383166313938
31376531366166333762623233646433323134663366323730613932393333333737623463653634
31356466646465333666363034343730313164353039646236393564326536323330363639343664
39363836663332333234396239336339356532626430653861373137333562623830653936323432
34306238623137313232333033356266303564376163333065653137616661643537373831666136
39303037383661313064396364363639346564643564303638623661356235336162633633616531
34626331393564363564613937346165333936366231333462633561356362616434306165343130
62346665653532663434396238366562336264656130643566666466313964303066373462373034
32613434363832626265636234343535313438313532643631363633363335653364393564356632
37613135343632613433616630333163323230333235363531343966333232646664393163386238
36613731656666663236316133353237636363663336656162316163393230346565366536376236
6336
33346333343637663032363331303231316234346636353763653039383662343730356335353730
6466653064643530393338663130613238343733646366350a666333636337356362393033393639
30636331653939323336313638623235393632663963303834613430386135633134343465383738
6139633438383937320a353536643230383439323339316638366464336636353164646232373839
35323165636364363238366431383663303430316130653366643263376238316137666665376366
61653937626264396531356639373865393962616565353265353366666133386266623638613138
38316632363065613234306661313431663639393862316630323064376236663332313130633465
37396136313032613932616664653239346265323135316131323735306638356664373336376231
34376565343531393831323438303563333463373437636535636162373830386135346164333264
37633264653932636639316161306637326361313530313365633335633937333832326130343532
39333739313364353539313262646364323931346436393633343063666238623363646338663862
37376565663636663166323030626133313065346135666439613032616135663136663062653032
34616433646266313462326261323166313566386266653962663435656232303036363235373632
32626461663936353236623564633366383366636666386236633766646439333161393438653661
39633362313337616139373663326364353534386231636561366664363862363833613133373031
30626664336166373938643935343138326564343036333266336331626638613238306262326261
30666265643435633565303365623633326466653837643633653934646638383736653365653730
66613365343730643635323032646363633934313263316534313263303533383865613636616266
66323435363037336239643366373534653434343063623130393437393633306130356666333339
30633533353563643832633064653165363563356436626637353833643064323432346131373230
32346433653332623535343366306662623638326462616463376333663830663039366235313766
31323665393964363262363366313764363965353439363865323464623632313833333235306237
30363937646335303066343934306130313330653266383239646462636364306439636163393634
65653638666239363737653632316536333535333134616664343665343030313637643333393963
38306338333033313064333339393239343631643563623765663362353764323661366161636138
30366166353364373139616562623634316432613662363539613765336335326266666666356332
34653263316663636530323431353562643833373935306264333565363832643030646433326263
38643462666237376331643037316232623664653333386433636566656366666430363337616130
31383730306563386465383531366462363266333437323831393561363665663231346362363665
35333836653931343161653261656265643732353837666337393835363536353937646561396365
64363463326435386330343937323934356366343434323964306131363133633434303266636563
39393463333539306262323239663033633830336433663931653433393030626633316564343737
31626461316234623965316339343434646561636164343037356566623366626636326663623533
63646166383835306430333965346234363334646534323566623430633865373837353763626663
37363461656430623739366664613832346135333535393531623762656566616137303439323039
63613436366161616263396464316231333535346561666631366464666433643031653231316464
62626363346335663639623366396634373664643965393339636336616139616431653830306331
37633439306365333961356336653637656661643763353032653063336430393638653830313439
62396632316166356131316438643164386466623162663661383834346633656265396438666231
61663332366634623032323836366235613933363964366665643330366466306434356232396330
39636163653536396365336631366633313830633631383333383338333964613034623935666663
66346434326630333630326333663462376431306432633466356166306532616530633262626231
36653936333134643832343865366333623939656539386534346430646330616431376366363265
33353132336562613139383264396462353234303533353263343433626566366263393134356666
65343633663261626138333665323238623239363364646436336639333636663236396162376164
62356534323663353832653466393837353931636232353331386534323934633336623039316662
30646432613761623966623033393533633235396431353631663364653461393464353738663031
63653931366633323966313664333562613263663239333937626536333662666538643736663034
38316365333033333130643931333331373662326639316266363436656365646262613433376336
31376663326563323637313339396263376231333230643238326339663239633463303435653035
39343533636234326262323330663736326431353637343663636165663935313236316337336463
33373033653435313235
@@ -0,0 +1,45 @@
---
# Playbook to provision Komodo stacks from git repository
# Automatically discovers stacks from docker-compose folder structure
# Structure: docker-compose/{server}/{app}/compose.yaml
# Usage: ansible-playbook -i inventories/production.yml playbooks/provision_komodo_stacks.yml
- name: Provision Komodo stacks
hosts: localhost
connection: local
gather_facts: false
vars:
docker_compose_root: "{{ playbook_dir }}/../../docker-compose"
tasks:
- name: Find all compose.yaml files in docker-compose directory
find:
paths: "{{ docker_compose_root }}"
patterns: "compose.yaml"
recurse: true
register: compose_files
- name: Build stack list from discovered compose files
set_fact:
komodo_stacks: "{{ komodo_stacks | default([]) + [{'server': path_parts[0], 'app': path_parts[1]}] }}"
loop: "{{ compose_files.files }}"
vars:
path_parts: "{{ item.path | regex_replace('^.*/docker-compose/', '') | split('/') }}"
loop_control:
label: "{{ path_parts[0] }}/{{ path_parts[1] }}"
- name: Display discovered stacks
debug:
msg: "Found {{ komodo_stacks | length }} stacks: {{ komodo_stacks | map(attribute='app') | list | join(', ') }}"
- name: Create Komodo stacks
include_role:
name: komodo_stack
vars:
komodo_stack_name: "{{ item.app }}"
komodo_server_name: "{{ item.server }}"
komodo_run_directory: "docker-compose/{{ item.server }}/{{ item.app }}"
loop: "{{ komodo_stacks }}"
loop_control:
label: "{{ item.app }} (on {{ item.server }})"
@@ -5,7 +5,7 @@ services:
container_name: komodo-periphery
restart: unless-stopped
environment:
PERIPHERY_CORE_ADDRESS: {{ komodo_core_address }}
PERIPHERY_CORE_ADDRESS: {{ komodo_core_host }}
PERIPHERY_CONNECT_AS: {{ inventory_hostname }}
PERIPHERY_CORE_PUBLIC_KEYS: file:/config/keys/core.pub
PERIPHERY_ROOT_DIRECTORY: /etc/komodo
+86
View File
@@ -0,0 +1,86 @@
# Komodo Stack Role
This role automates the creation of stacks in Komodo via its REST API.
## Quick Start
The included `provision_komodo_stacks.yml` playbook automatically discovers all stacks from your `docker-compose/` folder structure and creates them in Komodo:
```bash
ansible-playbook -i inventories/production.yml playbooks/provision_komodo_stacks.yml
```
This will scan for all `compose.yaml` files in the structure: `docker-compose/{server}/{app}/compose.yaml` and create corresponding stacks in Komodo.
## Requirements
- A running Komodo instance with API access
- Valid Komodo API token stored in `vault_komodo_api_token`
- Existing server and repository configured in Komodo
## Role Variables
### Required Variables
- `komodo_stack_name`: Name for the stack (typically the app name, e.g., "changedetection")
- `komodo_server_name`: Name of the server in Komodo where the stack should deploy
- `komodo_repo_name`: Name of the repository in Komodo containing the stack definition
- `komodo_run_directory`: Path within the repository to the compose.yaml file (e.g., `docker-compose/apps-1/changedetection`)
### Optional Variables
- `komodo_host`: Komodo instance URL (default: `https://komodo.{{ domain }}`)
- `komodo_api_token`: API token for authentication (default: `{{ vault_komodo_api_token }}`)
## Example Usage
### Automatic Discovery (Recommended)
Use the provided playbook to automatically discover and create all stacks from your repository:
```bash
ansible-playbook -i inventories/production.yml playbooks/provision_komodo_stacks.yml
```
This scans the `docker-compose/` directory and creates stacks for each app found in the structure:
- `docker-compose/{server}/{app}/compose.yaml`
Example structure:
```
docker-compose/
apps-1/
changedetection/
compose.yaml
turn/
compose.yaml
media-1/
arr/
compose.yaml
```
## How It Works
1. Validates all required variables are provided
2. Fetches list of servers from Komodo API and finds the server ID by name
3. Fetches list of repositories from Komodo API and finds the repo ID by name
4. Checks if a stack with the same name already exists
5. Creates the stack if it doesn't exist (skips if it does)
## API Token Setup
Store your Komodo API token in an Ansible vault file:
```yaml
# inventories/group_vars/all/vault.yml
vault_komodo_api_token: 'your-api-token-here'
```
Generate an API token in Komodo: Settings → API Keys → Create New Token
## Notes
- The role is idempotent - it won't create duplicate stacks
- Server and repo must already exist in Komodo before running this role
- Uses retry logic for API calls to handle temporary network issues
@@ -0,0 +1,13 @@
---
# Komodo API configuration
komodo_core_address: "http://{{ komodo_core_host }}"
komodo_api_key: "{{ vault_komodo_api_key }}"
komodo_api_secret: "{{ vault_komodo_api_secret }}"
# Stack configuration
komodo_repo_name: "homelab"
# Optional stack configuration
komodo_stack_environment: []
komodo_stack_labels: {}
+128
View File
@@ -0,0 +1,128 @@
---
- name: Validate required variables
assert:
that:
- komodo_stack_name is defined and komodo_stack_name | length > 0
- komodo_server_name is defined and komodo_server_name | length > 0
- komodo_repo_name is defined and komodo_repo_name | length > 0
- komodo_run_directory is defined and komodo_run_directory | length > 0
- komodo_api_key is defined and komodo_api_key | length > 0
- komodo_api_secret is defined and komodo_api_secret | length > 0
fail_msg: "Missing required variables: komodo_stack_name, komodo_server_name, komodo_repo_name, komodo_run_directory, komodo_api_key, or komodo_api_secret"
- name: Get Komodo server by name
uri:
url: "{{ komodo_core_address }}/read/GetServer"
method: POST
headers:
"X-Api-Key": "{{ komodo_api_key }}"
"X-Api-Secret": "{{ komodo_api_secret }}"
"Content-Type": "application/json"
body_format: json
body:
server: "{{ komodo_server_name }}"
status_code: 200
validate_certs: false
register: komodo_server
retries: 3
delay: 2
- name: Extract server ID
set_fact:
komodo_server_id: "{{ komodo_server.json._id['$oid'] }}"
- name: Debug server response
debug:
msg: "Server ID: {{ komodo_server_id }}"
- name: Get Komodo repo by name
uri:
url: "{{ komodo_core_address }}/read/GetRepo"
method: POST
headers:
"X-Api-Key": "{{ komodo_api_key }}"
"X-Api-Secret": "{{ komodo_api_secret }}"
"Content-Type": "application/json"
body_format: json
body:
repo: "{{ komodo_repo_name }}"
status_code: 200
validate_certs: false
register: komodo_repo
retries: 3
delay: 2
- name: Extract repo ID
set_fact:
komodo_repo_id: "{{ komodo_repo.json._id['$oid'] }}"
- name: Debug repo response
debug:
msg: "Repo ID: {{ komodo_repo_id }}"
- name: Check if stack already exists
uri:
url: "{{ komodo_core_address }}/read/GetStack"
method: POST
headers:
"X-Api-Key": "{{ komodo_api_key }}"
"X-Api-Secret": "{{ komodo_api_secret }}"
"Content-Type": "application/json"
body_format: json
body:
stack: "{{ komodo_stack_name }}"
status_code: [200, 500]
validate_certs: false
register: existing_stack
retries: 3
delay: 2
failed_when: false
- name: Create Komodo stack
uri:
url: "{{ komodo_core_address }}/write/CreateStack"
method: POST
headers:
"X-Api-Key": "{{ komodo_api_key }}"
"X-Api-Secret": "{{ komodo_api_secret }}"
"Content-Type": "application/json"
body_format: json
body:
name: "{{ komodo_stack_name }}"
config:
server_id: "{{ komodo_server_id }}"
linked_repo: "{{ komodo_repo_id }}"
run_directory: "{{ komodo_run_directory }}"
status_code: [200, 201]
validate_certs: false
register: stack_result
when: existing_stack.status == 500
retries: 3
delay: 2
- name: Display stack creation result
debug:
msg: "Stack '{{ komodo_stack_name }}' created successfully with ID: {{ stack_result.json._id }}"
when: existing_stack.status == 500 and stack_result is succeeded
- name: Display stack already exists message
debug:
msg: "Stack '{{ komodo_stack_name }}' already exists with ID: {{ existing_stack.json._id }}"
when: existing_stack.status == 200
- name: Deploy stack
uri:
url: "{{ komodo_core_address }}/execute/DeployStack"
method: POST
headers:
"X-Api-Key": "{{ komodo_api_key }}"
"X-Api-Secret": "{{ komodo_api_secret }}"
"Content-Type": "application/json"
body_format: json
body:
stack: "{{ komodo_stack_name }}"
status_code: 200
validate_certs: false
register: start_result
retries: 3
delay: 2