Files
MijnBesluit/docs/Uitrollen-met-het-venster.md
T
2026-09-27 14:21:31 +00:00

254 lines
13 KiB
Markdown

# Uitrollen met een venster
Twee programma's: eentje op je ontwikkelmachine met vinkjes en een knop, en eentje op de server
die het pakket aanneemt en installeert.
Ze vervangen de PowerShell-scripts niet — ze roepen ze aan. `Publiceren.ps1`, `Uitrollen.ps1` en
`SocketServer-uitrollen.ps1` doen dit werk al maanden, inclusief het bewaren van de vorige versie
en het terugzetten daarvan als er iets misgaat. Die logica nog een keer in C# schrijven zou
betekenen dat er twee versies zijn van iets dat maar op één manier goed is.
## Drie werkwijzen
De agent kan het op drie manieren, en welke je nodig hebt hangt af van hoe je bij de server kunt.
**Wachten op een opdracht — dit is meestal wat je wilt.** Je start de agent op de server, kiest
"wachten", en laat dat venster staan. Vanaf dat moment doe je alles op je eigen pc: vinkjes
aanzetten, op **Bouwen en uitrollen** drukken, en meekijken. Het uitrolvenster zet de pakketten in
je publicatiemap en legt er een briefje bij (`uitrol-opdracht.json`); de agent ziet dat briefje
via de doorgegeven schijf van je externe-bureaubladverbinding, controleert per pakket de hash, en
rolt uit in de vaste volgorde. Wat hij doet schrijft hij terug in `uitrol-log.txt` in diezelfde
map, en het venster op je pc leest dat regel voor regel mee.
Geen poort, geen certificaat, geen gedeeld geheim — en op de server hoef je niets in te tikken.
Met een VPN werkt dezelfde weg, alleen wijst `Opdrachtmap` dan naar een gedeelde map op je pc in
plaats van naar `\\tsclient`.
Het blijft met opzet een apart briefje en niet "er staat een nieuwe zip, ga je gang": anders rolt
de agent uit zodra je om een heel andere reden een keer bouwt. Een opdracht hoort te ontstaan
doordat iemand op een knop drukt.
**Zelf uitrollen, zonder netwerk.** Je staat al op de server — via RDP of aan de console — en het
pakket staat ergens waar die server bij kan, bijvoorbeeld op de schijf die je met je
externe-bureaubladverbinding hebt doorgegeven. Start de agent, kies "een pakket uitrollen dat op
deze server staat", en geef het pad op:
```
\\tsclient\D\publish\mijnbesluit.zip
```
Hier komt geen poort aan te pas, geen certificaat en geen gedeeld geheim. Dat is geen gat in de
beveiliging: dat je op deze server bent ingelogd ís de toegangscontrole. Wie zover komt, heeft
geen pakket nodig om schade aan te richten.
**Op afstand, met een druk op de knop.** Je pc stuurt het pakket naar de agent en die rolt het
uit. Dat vraagt wél een poort, en daarmee alles hieronder: TLS, een handtekening en een firewall.
> **Let op: RDP is geen tunnel.** Je ziet het bureaublad van de server, maar je pc kan daarmee
> niet bij een poort op die server. De luisterstand heeft dus alleen zin als je de server echt
> over een netwerk kunt bereiken — een VPN. Zolang dat er niet is, gebruik je de eerste werkwijze:
> bouwen op je pc, het pakket over de doorgegeven schijf, en uitrollen op de server.
Het uitrolvenster op je pc is in beide gevallen nuttig: bouwen en inpakken doet het altijd. Alleen
het versturen werkt pas als de luisterstand kan.
## Waar je je bewust van moet zijn
Dit gaat over de luisterstand. Rol je uit terwijl je zelf op de server staat, dan is er niets van
dit alles nodig.
**Dit is een kanaal waarmee code op je server terechtkomt.** Dat is niet een bijwerking maar het
doel, en het is dezelfde server waar de kluizen en de masterkey staan. Wie bij dit kanaal kan,
kan alles wat de server kan.
Daarom zitten er vier grendels op, en die zijn geen van alle optioneel:
1. **De poort staat alleen open op het besloten netwerk.** De agent luistert wel op alles, maar de
firewall van de server hoort alles te weigeren behalve het VPN-bereik. Dit is geen poort voor
het open internet.
2. **TLS**, met hetzelfde certificaat als de SocketServer. Zonder certificaat weigert de agent te
starten.
3. **Een handtekening per opdracht**, met een gedeeld geheim. TLS zegt dat niemand meeleest, niet
wie er aanbelt — en op een besloten netwerk zit meer dan alleen jouw pc. In de handtekening
zitten de soort, de hash van het pakket, een tijdstip en een eenmalig nummer. Een opgevangen
opdracht is dus na twee minuten niets meer waard, kan geen tweede keer, en past niet op een
ander pakket.
4. **Een vaste lijst met wat de agent mag**: de site uitrollen, de SocketServer uitrollen, de
databasescripts draaien. Er zit geen "voer dit uit" bij. Een agent die opdrachten van buiten
uitvoert is een achterdeur met een nette naam.
En hij draait alleen als jij hem start. Geen Windows-service: een poort die dag en nacht openstaat
voor iets wat je een paar keer per week doet, staat vooral open als je er niet bent.
Vijf zelfcontroles bewaken de handtekening: verkeerd geheim, te kort geheim, een ander pakket
onder dezelfde handtekening, dezelfde opdracht twee keer, en een opdracht die te oud is.
## Eenmalig inrichten
Stap 1 en de firewallregel zijn alleen nodig voor de luisterstand. Rol je uit terwijl je zelf op
de server staat, dan volstaan stap 2 (zonder `Geheim` en zonder certificaat) en stap 3.
### 1. Een geheim maken — alleen voor de luisterstand
Op de server, in de map waar de agent staat:
```
MijnBesluit.Uitrolagent.exe --nieuwe-sleutel
```
Zet de uitkomst in `uitrolagent.json` **op de server** en in `uitroller.json` **op je pc**. Niet in
de projectmap, niet in een e-mail, niet in een schermafbeelding.
### 2. De agent neerzetten
Publiceer `src\MijnBesluit.Agentvenster` en zet de uitkomst op de server, bijvoorbeeld in
`C:\Beheer\uitrolagent`. Dat is het venster; de agent zelf komt als projectverwijzing mee, dus in
die ene map staan daarna allebei:
| Bestand | Waarvoor |
|---|---|
| `MijnBesluit.Agentvenster.exe` | Het venster. Dubbelklikken, hij staat te wachten. Dit is wat je dagelijks gebruikt. |
| `MijnBesluit.Uitrolagent.exe` | Hetzelfde werk zonder venster, plus `--nieuwe-sleutel`, `--zip` en `--luister` |
Vul `uitrolagent.json` in:
| Instelling | Wat erin hoort |
|---|---|
| `Geheim` | De sleutel uit stap 1 |
| `Poort` | 5210, of iets anders dat vrij is |
| `CertificateThumbprint` | Hetzelfde certificaat als de SocketServer gebruikt |
| `Scriptmap` | Waar `Uitrollen.ps1` en `SocketServer-uitrollen.ps1` staan, bijvoorbeeld `C:\Beheer` |
| `Werkmap` | Waar binnengekomen pakketten landen |
| `Opdrachtmap` | Waar de agent naar een briefje van je pc kijkt als hij staat te wachten. Over RDP: `\\tsclient\D\publish` |
| `DbGebruiker` / `DbWachtwoord` | Alleen nodig voor databasescripts. Neem een eigen account dat mag wijzigen; niet root als het niet hoeft |
> **Let op bij opnieuw publiceren.** Een publicatie zet `uitrolagent.json` terug op de versie uit de
> projectmap — met lege velden. Alles wat je niet elke keer opnieuw wilt intikken hoort daarom in
> `C:\MijnBesluitData\uitrolagent.secrets.json`. Dat bestand gaat **per sleutel** over
> `uitrolagent.json` heen, dus je zet er alleen in wat afwijkt: `Geheim`, `MysqlExe`, `DbGebruiker`,
> `DbWachtwoord`, en `Opdrachtmap` of `Scriptmap` als die bij jou anders zijn. Het agentvenster zegt
> bij het opstarten in zijn logboek welke twee bestanden hij heeft gelezen.
Zet de firewall goed: poort 5210 alleen vanaf het VPN-bereik.
### 3. Het venster neerzetten
Publiceer `src\MijnBesluit.Uitroller` en vul `uitroller.json` in: de server, de poort, hetzelfde
geheim, en waar je projectmap staat.
## De vinkjes staan er al
Bij het openen kijkt het venster wat er sinds de vorige uitrol is gewijzigd, en zet de vinkjes
daarop. Het zegt er ook bij waarom: *"De website: Home.razor is gewijzigd."*
Waarom dat de moeite is: na een middag werken weet niemand meer precies wat hij heeft aangeraakt.
Dan vink je te veel aan — kost tijd — of te weinig, en dan draait er een website tegen een
SocketServer die iets anders verwacht. Dat laatste kost een avond zoeken naar een fout die er niet
is.
Wat waarin terechtkomt staat in `Wijzigingen.cs` en wordt door een zelfcontrole bewaakt. De
gedeelde projecten tellen mee bij allebei: een wijziging in Domain of Application zit zowel in de
website als in de SocketServer. Protocol zit in de SocketServer en in de app, maar niet in de
website — die praat niet over de socket.
Twee dingen die met opzet zo zijn:
- **Bij twijfel staat hij aan.** Is er nog nooit vanuit dit venster uitgerold, dan staat alles
aan. Te veel uitrollen kost een minuut.
- **Onthouden gebeurt op het moment van het nieuwste bestand**, niet op de klok van het moment
waarop het lukte. Wijzig je iets terwijl hij bouwt, dan zou dat laatste die wijziging als
uitgerold aanmerken terwijl hij er niet in zit — en dan staat het vinkje de volgende keer ten
onrechte uit.
Het blijft een voorstel: je kunt elk vinkje zelf aan- en uitzetten. Wat er onthouden wordt staat
in `laatste-uitrol.json` naast de exe.
## Uitrollen met een wachtende agent
1. Op de server, één keer: dubbelklik `MijnBesluit.Agentvenster.exe`. Hij staat meteen te
wachten — er is geen knop om eerst in te drukken. Laat dat venster staan zolang je werkt.
Controleer dat `Opdrachtmap` in `uitrolagent.json` naar je publicatiemap wijst; over een
externe-bureaubladverbinding is dat `\\tsclient\D\publish`.
2. Op je pc: start `MijnBesluit.Uitroller.exe`, zet de vinkjes en druk op **Bouwen en uitrollen**.
Meer is het niet. Je ziet in het venster op je eigen scherm wat er op de server gebeurt, inclusief
de regels van `Uitrollen.ps1` zelf.
### Het agentvenster
Twee vensters die op elkaar lijken, en dat is de bedoeling: op je pc staat het uitrolvenster, op de
server het agentvenster. Dezelfde regels komen op allebei de schermen voorbij.
Wat je op de server ziet:
- **Een balk bovenin** met wat hij doet: *Wacht op een opdracht van je pc* of *Bezig met uitrollen*.
Die regel is van een meter afstand te lezen, want dit venster staat op een machine waar je niet
naar zit te kijken.
- **Het logboek**, regel voor regel, inclusief de uitvoer van de PowerShell-scripts. Dat is niet
anders dan vroeger — het gaat alleen niet meer naar een consolescherm.
- **Een voortgangsbalk** die loopt zolang er iets gebeurt. Uitrollen duurt minuten; zonder teken
van leven ga je je afvragen of hij nog wel iets doet.
- **Stoppen met wachten**, als je hem wilt laten staan zonder dat hij opdrachten oppakt.
Sluiten terwijl er een uitrol loopt vraagt hij na. Een uitrol halverwege afbreken laat een website
achter die niet meer bij zijn database past, en dat merk je pas als er iemand op zit.
Er draait geen PowerShell-venster meer waar je omheen moet werken: het venster start PowerShell
zelf, vangt elke regel op en zet die in het logboek. De console-agent bestaat nog wel, en die heb
je ook nodig — voor `--nieuwe-sleutel`, voor `--zip` als je een pakket uitrolt dat al op de server
staat, en voor `--luister` zodra er een VPN is.
Valt de verbinding weg terwijl de agent bezig is, dan maakt hij zijn werk gewoon af — alleen het
meekijken stopt. Op het scherm van de server staat hetzelfde.
## Uitrollen terwijl je zelf op de server staat
1. Op je pc: start `MijnBesluit.Uitroller.exe`, zet de vinkjes en druk op **Bouwen en uitrollen**.
Kan hij de agent niet bereiken, dan staan de pakketten alsnog klaar in je publicatiemap —
bouwen en inpakken gebeurt namelijk hier.
2. Op de server: start `MijnBesluit.Uitrolagent.exe`, kies **2** en geef het pad op naar de zip op
je doorgegeven schijf.
Of, als je liever niets aanwijst, in één regel:
```
MijnBesluit.Uitrolagent.exe --zip \\tsclient\D\publish\mijnbesluit.zip --soort site
```
`--soort` is `site`, `socketserver` of `database`.
## Uitrollen op afstand (vraagt een VPN)
1. Op de server: start `MijnBesluit.Uitrolagent.exe` en kies **3**, of start hem met `--luister`.
Er verschijnt een venster dat zegt dat hij luistert. Laat het openstaan.
2. Op je pc: start `MijnBesluit.Uitroller.exe`, druk eerst op **Verbinding proberen**. Dat kost
een seconde en scheelt de teleurstelling van een kwartier bouwen voor niets.
3. Zet de vinkjes en druk op **Bouwen en uitrollen**.
**De volgorde ligt vast en is niet die van de vinkjes:** eerst de databasescripts, dan de website,
dan de SocketServer, en de APK helemaal achteraan. Een nieuwe kolom moet er zijn voordat de code
erom vraagt; andersom staat de site stuk in de tussentijd. De SocketServer is als laatste omdat
het herstarten daarvan iedereen met de app uitlogt.
Wat er op de server gebeurt lees je mee in het venster, regel voor regel. Loopt de verbinding weg
halverwege, dan gaat het uitrollen op de server gewoon door — daar staat hetzelfde in beeld.
## De databasescripts
De agent draait de scripts uit `db\` **vanaf nummer 03**, in volgorde. Nummer 01 maakt het schema
aan en 02 maakt de applicatiegebruiker met zijn wachtwoord; dat is inrichten, geen bijwerken, en
dat hoort een mens één keer met de hand te doen. Een agent die accounts kan aanmaken is een agent
die meer kan dan hij moet.
Alle scripts gaan er elke keer overheen. Dat mag: ze zijn zo geschreven dat opnieuw draaien niets
doet — kijk maar in de kop van elk script. Dat is eerlijker dan bijhouden wat er al gedraaid is;
zo'n administratie kan ernaast zitten, en dan mis je er precies één.
## Als er iets misgaat
Het uitrolscript zet bij een fout de vorige versie zelf terug en zegt dat in het logboek. Gebeurt
dat niet, dan staan de vorige versies op de server in `_vorige-versies` naast de sitemap.
De agent doet één ding tegelijk. Krijg je "er loopt al een uitrol", dan is er een eerdere poging
nog bezig of vastgelopen; kijk op het scherm van de agent.