Odoo-moduler för att hantera SaltStack-infrastruktur. Repot innehåller flera oberoende Odoo-moduler; varje modul ligger i en egen undermapp.
| Modul | Katalog | Beskrivning | Beroenden |
|---|---|---|---|
| saltstack | saltstack/ |
Basmodul: minion-register, pillar-ankare, felinjektion, inställningar | base, mail, cron_tick |
| saltstack_ai | saltstack_ai/ |
AI-brygga: SaltAPI-klient, tools, skills | saltstack, ai_agent_core, mail, cron_tick |
| saltstack_zabbix | saltstack_zabbix/ |
Zabbix-anslutning: settings + test-knapp | saltstack_ai |
| saltstack_wazuh | saltstack_wazuh/ |
Wazuh/SIEM-anslutning: settings + test-knapp | saltstack_ai |
| saltstack_zabbix_keykeep | saltstack_zabbix_keykeep/ |
Keykeep Managed för Zabbix | saltstack_zabbix, keykeep |
| saltstack_wazuh_keykeep | saltstack_wazuh_keykeep/ |
Keykeep Managed för Wazuh | saltstack_wazuh, keykeep |
| saltstack_keykeep | saltstack_keykeep/ |
Synka pillar-hemligheter till Keykeep | saltstack, keykeep |
| saltstack_helpdesk | saltstack_helpdesk/ |
Skapa helpdesk-ärenden från incidenter | saltstack_ai, helpdesk_mgmt |
| saltstack_maintenance | saltstack_maintenance/ |
Notifiera underhållssystem | saltstack_ai, base_maintenance |
| saltstack_managementsystem | saltstack_managementsystem/ |
Dokumentera avvikelser som nonconformity | saltstack_ai, mgmtsystem_nonconformity |
Lägg repot i Odoos addons_path — ingen symlink behövs:
# /etc/odoo/odoo.conf
addons_path = /usr/share/odoo-saltstack, ...Uppdatera sedan modulerna:
sudo checkmodule --multi-user -d <db> -m saltstack # basmodul
sudo checkmodule --multi-user -d <db> -m saltstack_ai # AI-brygga/usr/share/odoo-saltstack på ledningssystem är ett git-arbetsträd.
Koden kommer dit med git pull — inte via Salt-state:
# 1. Hämta ny kod (minionen når github.com:vertelab/odoo-saltstack)
cd /usr/share/odoo-saltstack && git pull origin 18.0
# 2. Uppgradera — --multi-user: parallell Odoo på ledig port (4444-4499),
# INGEN nedtid. Utan flaggan startas tjänsten om och besökare får 502.
sudo checkmodule --multi-user -d ledningssystem -m saltstack,saltstack_ai,saltstack_managementsystem \
-l info > /tmp/checkmodule-saltstack.log 2>&1
echo "exit=$?" && tail -5 /tmp/checkmodule-saltstack.log
# 3. Verifiera
systemctl is-active odoo # active
curl -s -o /dev/null -w '%{http_code}\n' https://ledningssystem.vertel.se/web/login # 200--update ska ta. checkmodule hoppar
över en modul vars manifest-version är oförändrad — även om koden skiljer sig.
Det hände saltstack 2026-10-11: kvm-källan (T/11817) fanns i repot men
versionen var kvar på 18.0.1.52.0 = samma som installerad → uppgraderingen
hade tyst uteblivit. Bumpa alltid version i __manifest__.py när modulens
kod ändras (assets/manifest-text räcker inte som skäl).
git status först. 2026-10-11 låg kvm-fixen ocommittad på minionen och i
repot (76bcf9a) — verifiera med sha256sum på båda sidor innan du kastar
dem (git checkout -- <fil>), så du inte slänger arbete som inte finns i repot.
-h postgres16.vertel.se -U ledningssystem -d ledningssystem). Den lokala
postgresen på värden har en föråldrad DB med samma namn.
odoo-tjänsten — den har Restart=on-failure
(/etc/systemd/system/odoo.service.d/override.conf). systemctl mask +
Restart= = permanent driftstopp. Använd checkmodule, som hanterar
stop/start själv.
Versionen i ir_module_module säger att uppgraderingen körde — inte att
koden verkar. Verifiera beteendet:
# Kod finns på plats
grep -n "'kvm'" /usr/share/odoo-saltstack/saltstack/models/salt_runlog.py
# Beteendet syns i data: kvm har egen källa i stället för 'other'
sudo -u odoo psql -h postgres16.vertel.se -U ledningssystem -d ledningssystem \
-c "SELECT source, count(*) FROM saltstack_runlog GROUP BY source ORDER BY 2 DESC;"Före fixen hamnade KVM-poster i other (62 poster låg där 2026-10-11);
efteråt har kvm 16 egna poster.
Se saltstack/README.md för full dokumentation.
Menyer:
SaltStack
├── Pillars (synk med Salt Master)
├── Minions (synk med Salt Master)
└── Konfiguration (sista menyvalet)
└── Inställningar (första menyvalet — SaltStack-settings)
Felinjektion (server actions på minion, admin only):
- 🛑 Stoppa Odoo
- 💾 Simulera disk full (växande loggfil)
- 🚨 Simulera Wazuh-säkerhetshot (brute force i auth.log)
- 🧹 Rensa felinjektioner
End-to-end-simulering (server actions på minion, admin only):
- 🧪 Simulera full larmkedja (stoppa odoo) — injicerar felet, bygger
webhook-payload, anropar
/saltstack/alertinternt, startar AI-diagnos - 🧪 Simulera full larmkedja (disk full)
- 🧪 Simulera full larmkedja (Wazuh brute-force)
När ett larm kommer in via /saltstack/alert startar Infrastructure Operator
coworkern en diagnos. Denna ändring (2026-08-12) tillförde:
- Chatter/writeback — diagnosstart, resultat och åtgärd postas på
saltstack.alert-posten (via mail.thread), sammanfattning på den berördasalt.minion-posten (med klickbar länk till alerten), och åtgärdsplan i Driftlarm-kanalen vid severity ≥ 12. - Auto-fix-taxonomi i diagnos-prompten: säkra fel åtgärdas automatiskt (odoo/postfix/dovecot nere → starta tjänsten, grow.log + disk > 85 % → ta bort filen, Caddy 502 → kolla upstream först, sedan reload, PostgreSQL nere på replica → starta, ALDRIG primary). Övriga (OOM, CPU-spikar) dokumenteras bara → helpdesk-ticket/nonconformity.
- Odoo ORM-verktyg från ai_agent_core (
describe_model,odoo_search,odoo_write,odoo_call_method,odoo_create,odoo_unlink,okf_search) är tilldelade Infrastructure Operator — AI:n kan svara på frågor som "Hur många minioner kör Odoo 18?" och skriva tillbaka på poster. - Zabbix Troubleshooting-skill (5-stegs metodik: problem → trigger → item-historik → korrelation → Salt-mappning) bunden till coworkern.
- Helpdesk/nonconformity-verktyg (
create_helpdesk_ticketi saltstack_helpdesk,document_nonconformityi saltstack_managementsystem) binds till coworkern när respektive modul installeras. - Källspecifik avstängning av AI-diagnos (2026-09-12): bas-modulen
anropar
_auto_diagnose_enabled_for_source()iprocess_webhook— en hook som bryggmoduler kan overrida för sin egen källa.saltstack_zabbixanvänder den: inställningen "Auto diagnosis on Zabbix alerts" (zabbix.alert.auto_diagnose, default på) styr om Zabbix-larm ska AI-diagnostiseras. När den är av registreras, dedupas, korreleras och notifieras larmet som vanligt — bara diagnossteget hoppas över. Andra källor (Wazuh, Shuffle) påverkas inte. Kräver att den globala "Auto diagnosis on alert" också är på.
Buggen: ir.config_parameter.set_param(key, False) raderar raden,
varefter get_param() faller tillbaka på fältets default. För en
boolean-inställning med default=True innebar det att kryssrutan inte gick
att bocka av — den studsade tillbaka till på. Gällde både
zabbix.alert.auto_diagnose, saltstack.alert.auto_diagnose och
saltstack.alert.webhook_enabled.
Fixen: set_values() skriver ett explicit 'True'/'False' som
sträng, och läsningen (_auto_diagnose_enabled, _auto_diagnose_enabled_for_source)
använder _get_param() (returnerar None när raden saknas) så att
"aldrig konfigurerad" = fältets default (på).
Tester: saltstack_zabbix/tests/test_auto_diagnose.py
(test_setting_can_be_turned_off_and_sticks, test_missing_param_reads_as_on).
Tester: saltstack/tests/test_salt_alert.py (chatter, prompt, simulering)
saltstack_ai/tests/test_tool_access.py(ORM-tools, skills)saltstack_zabbix/tests/test_auto_diagnose.py(källspecifik diagnos-gate).
sudo checkmodule --multi-user -d ledningssystem -m saltstack,saltstack_ai -t- Rena Odoo-repon — varje modul i egen undermapp, addons_path direkt mot repot
- Inga symlinks i Odoo-repon
- Inga pip-install i Odoo-repon — använd
--break-system-packagespå Ubuntu 24.04+ vid behov, aldrig i repo:t - Alla hemligheter i pillar/keykeep, aldrig i kod
Proposals och specar ligger i openspec/:
openspec list --jsonBeteendeförändringar som operatören märker:
-
Synkintervallet finns inte längre i Inställningar.
sync_interval_numberär borttaget. Intervallet sätts i SaltStack → Konfiguration → Schemalagda jobb (registret), där ändringen loggas. Inställningar har en knapp som öppnar samma register. En sparadir.config_parametersaltstack.sync_interval_numberanvänds inte längre och kan tas bort. -
Schemablocket "Background Jobs" i Inställningar är borta.
saltstack.cron.lineär borttagen. Samma information — och mer — finns i registret: körhistorik, felmeddelande, lås (locked_by/locked_at), hälsoläge och överskriden deadline. Registrets "Kör nu" går genom samma låsta körväg som schemat; blockets egen knapp gjorde inte det. -
minbetyder 5 minuter, inte 1. Backfill och auto-resolve gick från 15 minuter till 5 (förbättring). AI-diagnoserna gick från 1 minut till 5 — kompenserat av en webhook som startar diagnosen inom sekunder, så nettoeffekten är en förbättring (60 s → några sekunder). -
Ett jobb kan stänga av sig självt.
cron.taskavaktiverar sig efter 10 konsekutiva fel. Enir.crongjorde aldrig det. Det syns i chatter,last_errorochactive=False— aldrig tyst.
Oförändrat: restic_snapshot_sync ligger kvar i ir.cron med
nextcall 06:30 (ordningsgarantin mot rapporten 06:15). Dirvish-synken
ligger också kvar — den ska avvecklas av minio-snapshot-tab, inte
konverteras.
Inte löst: SerializationFailure på salt_minion.open_alert_count är
ett samtidighetsproblem mellan fyra skrivare, inte ett schemaproblem.
Detaljer: saltstack/README.md → "Schemalagda jobb" och
saltstack_ai/MODULE.md → "Schemaläggning".
openspec/dev-environment.md—jakob18(fri utvecklingsdator) vsledningssystem(produktion). Läs den innan du startar Odoo lokalt: en enda trasig modul iaddons_pathfäller hela registret, och 86 ogiltiga manifest finns iodoo-fortnoxm.fl. Innehåller receptet för isoleradaddons_pathoch testdatabas med pgvector.openspec/changes/— pågående ändringar, en katalog per ändring medproposal.md.
ledningssystem är produktion. jakob18 är fri.
jakob18 |
ledningssystem |
|
|---|---|---|
| Roll | Fri spelplan | Skarp drift |
systemctl restart odoo |
Tillåtet | Aldrig utan checkmodule --multi-user |
| Databaser | jakob18, cm_test_*, pi_*, test_* |
ledningssystem |
| Får gå sönder | Ja — det är poängen | Aldrig |
Inte fritt ens på jakob18: /usr/share/odoo-fortnox, /usr/share/odoo-payroll
m.fl. är andra repon och andra kunders moduler — ändra dem inte som bieffekt av
eget arbete. Delade resurser (postgres16.vertel.se, Salt-mastern, Zabbix,
Wazuh) får aldrig skrivas till av en testkörning.
Fällan: addons_path har ~132 kataloger och Odoo validerar alla manifest
vid registry-load, inte bara de installerade. Ett enda 'version': '14.0.0.0.1'
räcker för ValueError: Invalid version och hela uppstarten faller. Bygg en
isolerad addons_path med bara det du testar — se
openspec/dev-environment.md.
Baseline: kör alltid sviten på orört HEAD (git stash) innan du rapporterar
"mina tester är gröna". Per 2026-10-23 är saltstack + saltstack_ai
52 tester / 7 fel på orört HEAD — alla i test_salt_alert, pre-existerande.
"0 failed" är inte målet om baseline aldrig var 0.
Ett store=False-fält utan search= får inte användas i en <filter>-domän.
Odoo kastar Unsearchable field "x" in path "x" vid vyvalidering, vilket fäller
hela modulinstallationen — inte bara den vyn. fields.py:
_description_searchable = bool(self.store or self.search).
group_by på ett icke-lagrat fält går inte heller (ValueError: Cannot convert … to SQL because it is not stored). Använd ett filter i stället.
['|'] * (n-1) + leavesär bara giltigt för n == 2. Odoo-domäner är prefix-notation: en operator gäller de nästa n termerna. Med fler termer →Domain ... is syntactically not correct. Använd_join_domains.['!'] + [A, B, C]negerar baraA. Bind konjunktionen med'&'först.not ilikekan inte uttrycka "värdet saknas" på en CSV-Char.'postgres,odoo' NOT ILIKE 'postgres'är sant i SQL. Negera hela den positiva domänen.'not =ilike'finns inte som operator.
AGPL-3 — Copyright (C) 2026 Vertel Sverige AB
- Logga: visas till vänster om namnet i formuläret (Odoo 18
.oe_avatarfloatar höger — överrids medstyle="float:none"). - IDENTITY:
private_ip,public_ip,external_domain(t.ex. svenskfast.azzar.org),has_gateway,os,dc,roles. - Odoo-fliken (visas för Odoo-minioner): Odoo-version, Odoo-databaser
(komma-separerad,
(demo)efter db-namn vid demodata), antal användare, senaste inloggning, antal AI-medarbetare + M systemtokens (1M bas per medarbetare + extra budgeterat viamonthly_cap_mtokens). - Kund (partner_id): sätts från
customer-grain, fallback till minion-namn-baseradres.partner-lookup (_search_partner_by_name). - Kugg menyn: server action "Uppdatera grunduppgifter"
(
action_update_basic_info) — grains-sync när fält saknas/är gamla + Odoo-statistik (bash via Salt API, läserdb_*ur odoo.conf, kör som root med PGPASSWORD). activevisas inte som fält — inaktiva minioner markeras med ribbon "Inaktiv".
keykeep.credential.minion_id— kopplar nycklar till minionen (sätts vid pillar-sync och masternyckel-hämtning).- Smartknapp "Keykeep-nycklar" på minion-formuläret: räknare + öppnar minionens keykeep-credentials.
- "Hämta Keykeep masternyckel": läser
keykeep_encryption_keyur minionens odoo.conf och valvar den som keykeep.credential (krypterad, auditerad) — en av nycklarna är masternyckeln. - "Deploy keykeep key": kör
state.apply keykeeppå minionen (Salt state/srv/salt/keykeep/init.sls) → genererar Fernet-nyckeln idempotent (bara om den saknas), skriver till odoo.conf, startar om Odoo.
salt.minion.storage — fyra rader per minion + summa:
| Rad | Källa | Metod |
|---|---|---|
| LXD-host | container på LXD-hosten | du -sb <pool>/containers/<minion> på hosten (dir-pool, t.ex. /var/lib/lxd_ext4 på fors). Host detekteras + cachas (lxd_host, saltstorage.lxd_hosts). |
| Dirvish | backup-trädet /srv/backup/<host> |
Dirvish backar HELA hosts → per-minion-andel = minion-LXD × kvot(dirvish/LXD). Kvoten beräknas med bakgrunds-du (nohup) + cachas (saltstorage.dirvish_ratio.<host>). |
| S3 (Garage) | kundens src-bucket | restic-status.json på restic-minionen (customers[].size) |
| S3-backup | restic-backup-bucket | restic-status.json (customers[].backup_size) |
- "Mät storage"-knapp + gear server action (
action_measure_storage). - Rader är redigerbara manuellt i fliken.
- res.partner: smartknapp "Minioner" → listar kundens minioner.
- Minion-listan: IP-kopiera-ikon (
saltstack_copy_value), domän-öppna-ikon (act_urlny flik), dc, lxd-host, storage-total, odoo-användare, 1M systemtokens. lxc.list-Salt-modulen saknas och bulk-target (L@) är opålitlig via netapi → sekventiellcmd.run-probing med korta timeouts + caching.