forgejo-runner: convert to a role, de-Uptime-Kuma the health check

409-line playbook becomes a 16-line playbook plus a 318-line role with phases
split across tasks/{prerequisites,install,configure,service,healthcheck}.yml and
four templates. forgejo_runner_vars.yml is deleted; its content is the role's
defaults.

Applies the Plan 6 Stage 0 decision: keep whatever determines whether the
service is healthy, drop the Uptime Kuma specifics, make the reporting point
pluggable. Gone from the role: the embedded Python that created monitors over
the Kuma API, the /tmp credentials file, token extraction, the systemd
Environment= rewrite, and 8 `when: uptime_kuma_enabled` guards. What remains is
the check itself, its log, the systemd unit and timer, and an honest exit code -
`systemctl is-failed forgejo-runner-healthcheck.service` now answers the
question with no monitoring system involved at all.

Reporting is one variable, healthcheck_push_url, empty by default. Any endpoint
that accepts an HTTP ping plugs in there. A pull-based monitor wants it left
empty and reads unit state instead.

PREMISE CORRECTION: Uptime Kuma is NOT dead. Plan 3 recorded "48 push timers
curling an endpoint that no longer answers" and Plan 6 said the check had
"nowhere to report to". Both wrong - 24+ push scripts across 11 hosts are
pushing successfully right now (HTTP 200). Only the Ansible code and the vault
credentials were decommissioned; the service never stopped. So the existing push
URLs were harvested into a vaulted healthcheck_push_urls dict and are preserved,
keeping this refactor behaviour-neutral. Retiring Kuma stays a deliberate act
rather than a side effect. PLAN_3 and PLAN_6 are corrected.

Verified:
  - task-list diff vs the old playbook shows ONLY the five Kuma tasks removed,
    everything else identical and in the same order
  - first run ok=22 changed=1 (the rewritten health script); both systemd units
    and forgejo-runner.service came back ok, so the templates reproduce the
    previous files byte-for-byte
  - second run ok=22 changed=0, fully idempotent
  - still reports "Ping sent successfully (HTTP 200)" from a script containing
    zero Uptime Kuma references
  - the 4 skipped tasks are genuine already-configured guards, checked not assumed

Two things for the next service:

- import_tasks, not include_tasks. Dynamic includes are opaque to --list-tasks,
  which is the primary verification tool here; the first attempt produced a
  useless diff.
- `Assert runner is running` was guarded by uptime_kuma_enabled and so had not
  run since the decommissioning. It is not monitoring, it is the deployment
  checking its own work - the deprecation banner swept it up with the Kuma
  plumbing, and a runner that failed to start was deploying "successfully" in
  silence. Ungated now. The banner was applied to contiguous blocks, so read
  every uptime_kuma_enabled guard and ask whether it is monitoring or deployment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
counterweight 2026-09-12 18:15:29 +02:00
parent 2ebb2f9a64
commit 73340d5fbe
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
16 changed files with 710 additions and 528 deletions

View file

@ -1,60 +1,162 @@
$ANSIBLE_VAULT;1.1;AES256
61356165613635386631393135656434646436303665313031346566323336313138353433316463
3363323534613064643132663335623238366431393062340a346538396662306537663163623366
38626166383933616331623231373137306562623637313263333237633661663436666266616433
3862346438643638650a306634333535653633613534646630386131333236366538333765323333
38656163303837303732663561373232393132343331663164656262393730326434373731333636
36613538646431396536363936336562616431656665653965373864633366663836353434626434
34383932373461333564303439623565383661646365386665393831383463663662356536356236
36373964666236626465366161636135393734356536633466383262326537343833636630343738
62353066316131613737373162643363653662656261363465386364323962656537373061373032
33343763353464383438363438343965653532393831343930393562633630383932653862623637
38386239353237356631646436356166373961333464396639383538383662326534343339313330
65373339356364636634616532363832386631323062363530313861336238353261353334306235
62616338396431316537346638656365356564346666366366343638356261623664393263323937
30343261363562383332323462336435376664386134646562643836363834313237373631353731
35653535663864643266313332356635363262363533663232656531373130336539633066376139
32316665393831663035623962656364363831333563366135636164346335383738363336663566
63356532643563393939383635386462663561386434323939303431653438653131363538383034
33623933333464363032656636643033326162626163353633343062633966343332383138363963
36383831663562616533316436366566323061386535343538393861383462333166343562316633
30623665623035393537393965626363323132656433313339396233356666346634316332616336
37363635363330323230373332326565343530653335383437373230366563366237633665626331
66623336626230663361636439316337393865383035326136653264666438666566646132353036
38616264313833316536623238633339373466613866626366383835656638623863323838653030
63303938376164653966356435386333363731656666313234663535666165646233313137343563
36386437393139656438333262383437656666343831313239323961373637653163643664356565
62346431393133656530316262303763646165643336396661666431383436323562336137653031
62626538373839613734396366653065306534636630346338316237616161613037616364356431
38643965376133616161336633383664326230383435363334353137303162663738313331346238
39356161616533616134356231323530306338333162343363353531303263636632613036386638
63633136386232306234323936303563646466313935326631396565383432386130656638616266
32383334363237336539396665336366643764633131643663643137376438323666326435626461
64346633636431393137633537306431646564386565303933636434386462346630626537346438
32623333666133303061646564366366326665363163396262633164323631636337346130303239
38373936663337356134666132303165393365663763396362623434633737373538653566646134
62316164396438303532616266313062326666633130656338653139376634306664633031333037
31636166306565353334633435656233336233363664306264626237623366336161303134353433
63383739666462623336386537346662633666626466393039653439346436653937633537396436
35393339383066326630353066623132333034656539363561346462626265363263303535343961
39316461616630326539613731303039613736393633373338646266323938326162373831346336
30656130343463366534323030646238313465306266383034623065636665623366333063383736
38373063393837306462303564643962373334343139626338623935336435643730646532633630
66363730386636633639346463363365343239373265303738353732653633653437636130636664
39386365353334653765343335303263363461313965383664326563333734626533376436626530
63353163323637303730353564383733653365613635353764333266393532653663326533646132
39313763373735323835626437306435373238653432393936643165663663656665316132653330
35383038353532656434366336346235363563636264303734633138323963396562306232646236
38366536306561653937336333373434336164663336613839353439356435333833396363636437
38323934613735643363656233333037336465336564313966623063376566663030303230323262
65643564666534326234306164343365383632333061316238623565353538313538396364313337
35336230313339643736653238386231343661623337306236383665356632366236356335323530
66373831616239376231636361333430343433303233393066323865663434643433303832373262
36366534646161323130393931626362626139663139643263366639656531613436313533363130
65643736363833333939613566663339623964333262643863333030623138633464386238613934
31323639333234336264313663376465323737353766643839303665313737336534386665363034
30326439666433373232306136306365343764643434306561343339353132346430646436343362
32333765616262363930353435616563333736313533653339656231316230346166363335356638
37333561366339613136306438306130343230663732333862663838396463623661303961336433
65646332373139303462303633346432366530643130366133363937653739653036366136373434
343864373734666431326239373866313734
32333164303734353564643266316239636365313631613866306666643538353537323939373066
3439396330326266396531303737363131313831396365650a343832363564356337396530383438
36356465623634623361643436383262393339663134373630666363613464653437666164393731
3462326463346535310a396531393761643062643563613964613234666531643139666535323734
63653630616138373539343434636434326466353134643864396466373435613738653536356532
36313432373138316532663464353638386530666231376636643931663338303663346665363039
39323734343934393037633766626132333835363265653538373266323236336137356630353834
63306164313434363130306339346435643463376137366534643033366537383861363531353861
34363966303234333133336466646635623136396138663637613133613861313866646634643132
34383461366133333430633631353561653037346339626165346564353630373363643065323535
61386237353135636665363538623538313039343965363535323734653763366238373334323065
64626135383736316135303731656231313263306266636563343465653666326663333536383435
32643537616161623830656161633763303566656462356235633866303165383663386435363133
61353430656337656364646231383332316534316233393333646436353062316461366439613030
62346366383566356661376463616137373062303363346333636134633465396238343761363139
38616336633532366165376237626337333933353935613066303865303536303464633834643533
31376236333133336166373635626130316632396561393930353065616465663336393938323539
35343531306261343733626539346265386436643135326461353734346164633233383237393731
32303030623564666539383835333064323630393539393062313435383663303334383134666436
63336564353464313534323866383533323365393761643565633430346263346666623638303030
38653461616661346661316537306666313165613163303835363636616561343335623131636633
36636263356530366663616461316635316365393666313066326265306335363038366561356339
37366231656330643764613664653735633963666638623961653134316136666336396438333864
65653738623638373636366666663463373035363862396565396166643332343934626261353938
34666638383531366532663963323533323965373439623735353661373862393830623934313535
62363237663764356338383133336463303234393262623061363062373938613262383836323431
35336133306139386336373965393132393431343535306162383337643961323039373530646330
35383962303263353234376164633530666264386338376335653465616161383532613830636562
36613837326564313565633632353964346537303337316233623033383961363737313861393234
64313130306264636134626638396661353362346439373463663965653165613436363633323238
39356430613033643334363731346333346639643563633162333636653066386233373063653138
38623630353265663332366630316362633135633362313735306533333962373433376237366266
64643266323862383363633033656465303032336134623036646530323264323532653234306363
64326663343064643865373164306661613463366561383737363535303861646634353139636666
66626466303037363064303865313830356531313834353165303839326238613962313261353536
63626133663765373763623930623963653038313661656131666261356236366565626663323831
32313130366135616662616639386436656265346635613762353832626466323261346333373661
33656338326631393064313762343161363832643030303737663639356261633131353937396135
34666361353266373661626534353134663235343662636435383032636261636637636361613631
30373965373638386664313432386264303761376266363161363633343831633032356639343836
36306163303363353534313466353863633834393337303161313431343165346162653537346130
36393439386232613865613837346563643031393530646433353936383463303562326331313738
30646537616264333332323562363237323530313333386531323066343335323133366566383935
34613232323965626339653132323162626234356135323436353263306137343130346337326531
62396164386661303366363566393833353130643636613865616433633166666532653937646262
63323530616533373962626264633236313064306336633063356536343862316237383166346264
65666466366435653134303164613632666336626630373764333534393164303132656530343031
32386137633135376531373662336131313030303436333833663234343938323232343832633234
35623361393533316232393431646561616535643638383533353266646235313736356366343231
30383962353833326161663534396565316139393439366631313731663737656332646361326331
35623038343931666231653731346435653162326237376339663936343933346264343564666132
62393230363262323366313963373737646138336163313434376462383964396337313030383831
35643865303738393736323032353239633631306262663536663732623933383431383563646664
65326230323239353831623232633935636632636438636165376633313364643637373233323231
30323534333131623138636266396565373964633963626536383930316663656634636638316363
36326438363463386138633133346666383163323936653131666339333430316363393966316130
66333732333565646564303633373464666461373437656634306564336432323465386631323034
32376635666139313465393539353438626534646332323537363163653233353030366231306234
31663065393062633438343438303762633931653564366666336662323430366466333334303763
64356138373035323862326137643963323865666539316439333064343961303838636265623735
36636233373065303239363461373239646662346162326164613332373761326561656234636438
39636231386531353236303933343661393333383730636366626263393534656363366337316432
66393162313731616165343362643162376334346262353730653738323138646463666433383963
31626131373736633662366366376566656438343330383330616235376239353661663663313233
63373836363638366432376130633930343862613436633263613538336536616163656364656561
35353163323663663833343834373036366531623536303138613035353064303065623761376462
32656363613765316635666639383865636538326130386535316132623238393730353631346136
65353864393863376632356437303565626262343039636436636335383337623465336263623439
61393030636466303836663166613766326164626639313965373734643466373663343565343631
35356431303139396131346335346664373830663361616136306535643431353037636431343132
32613164333232346335663236343238653033643133316564666534323130373861623962393461
62386336326461326239383534303631346639343765393839656364353762356266653733303238
37393533366164393863373134633439383765616435346239333065623438353431663035306132
30363663383765356365333234323061326163653463646566373764363037373932623032366133
64626633643737323631306539333531343239326639643166393435323731353932336262633963
62363561616635356230626431626232383439633738306532636361336334616238643665323266
35666165396566323639303733623364353436613966336337656363633762393664303939656537
33656431663431396237643536613233376561313261323635613634613439633533393361333435
33616136633936386135623563616530663833643339623439366430646639646162613863643565
32343732613134656332653163623437366637656537666334653239366638653537393639396234
63613362623037663465626438646136396362663033376261376166306138363436666566393838
63363262386261316432313235323166333334346539343663303265303535636439653130366566
38383632326433323036356266646138366233656131663633613236303137336437383333653430
35653738623635656661393232333334643937303631663464383239353635393735353833333265
38303831623130303634666464316465653639383230623662326534333136616561666166613930
37643632393265326364376230643634356538626337633638663634326538396536383633303633
62613532336435326161626263376462363162303762613835663831623539623562336361333031
37346438343230363433633738643064336235323438346534643463333930626430653131623538
61363735336332633663383136613633376430303133366634643839636562656431663737336431
65653164393331626532356566623830623931373431393330633638306663376566346136643863
61653461633637643663303761326464636339336635383938633039613132336139663762363734
34313831366232383562363834653232613665616266323033336635653933626630346132643164
66336663363161616431316666383430326266636134396239656561643763386438306434373166
65616637356366353336346539396665396364383162383533323837303134313664326338366131
64336333316531353661616561656430386462666565373535613134336634383136613638323565
34303130316162376137303137396330343466383263363638306334386161613535303735623537
30613065383963666166336135663632303038326163346630376466393761663738653532333466
35346161373237383766393063623939363664356639653862353132353930383261643761363135
66323364376432363437656239626362313835333537663030386435623764373937636130663331
31663636616261636663306230653264353566313966333665383938393731336538363665636665
33383334613565393139613138633636656234386263663932323364653361623433326438326132
34636633663838636634323236636564333630666362356333333230346333373833653365363135
37326630386439356139653865643039666237313833306161643263663363393965633163366436
65373132623265363134343233653366383665633163363766353066653863373937613631373332
34653835636565353731396331633133393435373739306663343632323234633462356630666238
36316634303031346138393835363565366131663534323933623166653662323931386135363432
36626434323536326636653165626661386663393134653061326634633162653666393661353762
31343766383933633261366437396332356362663539623032663435356231656430366532623535
35636361343330333263636230383030326139323065373032376238333162343462383566333264
66386439303163616638353635303736376461326533623234633264353865393065363765366636
63383034373631656331386439633863613731633930646330613931303430366236643735633434
33346638356330643534396236633630616134626237613363306334383639336161306235626133
32616339633033343431633131666131383036373335303739663634653831376563363034363365
63366532393761323862373434656264323938313334333234323162353663306263636435653636
65343531663234636362623139653439386132316430346536623864383539313037666439643638
35323235303164396361383832303362613235386530303538376265373964623363653365383961
61306365346532336164303763396364363038646563323562653865303461353339366334376534
61346230343662336633316133666631613136316537393464666635643336393566613730333837
62643232623831333730313737666536353137613138333566323934353236616464656238303339
63346665326661653832646466636165366338376638353431346130323230646534303137386634
66646362663831623234333335376561336664343232323361326430313138633266343065366535
39396463636330663738333033616334623366643636623735396435643865396630656234333433
63346437663331653233313430666633366264343565373838656536323231633966663262346434
35386631333063666233303364346139336461333736366438396239353136373339636638323534
61663564353733363131363139663761646561313337656232336164653234646563666266656362
36613666303165383530386530646331346661323633393232376533386661376533663166346337
63316431393964333731373332313732643765386662656437373136663532663531383436393761
36323939643464343035313633313436373038646234343366356264386131623462343161313261
62383839343863386365366432396666303065616137396631373330643339656433363463313131
30653431393630653331633634363233323632306434626566393662323566613565633639313938
65626434353530306630636430646261373365386538613232383663336339303838626533306164
62386166363861613863393331343362303665613239626265316366386165633264636163343366
30643965633239333162633433366132323162396564383530373839333331643632333930643035
33313663623165613033353130616666643136303137356462613237653430366663653061653035
64653961343163646530623863313663303231633764626264363366613162313535653631656365
39633561643833313334363465626263656132623463633335333465306266373634386238666165
37373134646438303134653734323665666531626533666663363534316238666232316438393939
32633531313565636531646361356566663133316164623133653935313335323835616238336431
61663664393239343837353039303334353035323861323533663161376361353933313032306136
36623463363235303166616162373665616333346366336333333531623932376664383861616232
38393263336364343566653735396561363836373064346131336366316231303539386531643835
34363463636232653137656339643630336333653163383332663763663633393837343963336666
61316236366436363064396464383138373639373864636261383533333139306237303030373037
36333563653036393734393439636262303837356133636233663064623136356133613932656365
62356630323134373063663664316133663761383035633065383838333364663732353866356230
33333263316666323133323433653330646161386462303163303235343031343761633234306166
63363138376531353130663431636637646262366436393161376633306332346465316333656432
34333238306263666537626231376665376435623466643131363736656432353938653236656132
37313633323863656463633030336566343265666534663737396530316234343433383931336462
35306236626564373766393438653134353332616532373132336663626130666532373933323863
39656463386136646131356462653933306532383232313334326334613738356339623566636661
62373139326138326663666237663436656631343635373733626439643466326439663361313266
61323966336532653263633530646363366439326663356664313065306166313863396439396564
30303138326261303661333831306536333363663536323235356263623533346233386161396131
64356265363964316231333933613463623163316538393830393539306533313035303765656437
38623262333662613665396537323331393937366533303039386138643639383664663263643734
65313531343636393232343230613639363466616235633162353430646364363934393530643263
39633539333237653733363132303163613564623232313464376336306431666534653338323765
35646564653736383962343664383666333936363864396334333463313637343336396434633766
35396466306235323338393937643362373764613161333462303665646239636562306635663330
3630

View file

@ -1,60 +1,162 @@
$ANSIBLE_VAULT;1.1;AES256
34616531626537376463326332306434383163393761363536633133363161373631376437653234
3831656536313531343433376264643261396634633965370a303931336236323766313065636535
31343338616364386132623232373266663665353563666535383232666262663062323864303932
3439373734316639650a633732333064633335383833663261326464336538636666323063646331
66653464636534663935616461636132613162303530663237376661343338396133323431623561
30303563303465633231306339326561313533333536376433393130376634303932643339656336
30616130343733626162366561393939393766623138616537393032376665396139333561623830
33623130336235633034666561383165616439316334323664623661343438663733373833306335
30396165313731636435636263353133326135346236323030653734353831626238666663656364
62386164363361373464383730333733626333333736306535336635613634646535383237326332
37636532663933663739303634333235343137333363316430643263326231613635643633636437
30336462633233396430633939616661643261666136656363363461343230653738613166346434
63376363666462346539343063343562623962303130616535306439653134633630353963373337
64313239353162363862643432666438383330636638333464323731643163643236313535313030
65656231383738356537326661663163376634613031396436646633376139313237343534653065
64323532346133313265346334353530393633396339316330366536646565353836396662303866
65373030393463306664623235626437613965303837313365373632643935656630303936373837
64663539623764656636613263346638376665626262663430333231633735653563643864343835
62303637383332653366383066326536316336306539623230353066343739316430356437313365
33323031613130643832636133636263303565623330306135333762363036633737343933623437
33633436363062643436376632336235666330656265316333323361316430656631383734343238
65616366666536363866343361666563643336306532666332643230656264303565353032393932
36613738326239376161383064646634623639356439663965323237303361343838373737636235
39656465333063633136643463356564636537326339653033633063366265636138656466646264
32643961343863656464353439346531633036613138353333353631626665396239326465303632
39336664333038636435366333623336353963323535316436646136313739373537376537353735
66333265633232346536313933333836643439656666636236626266323333383935383565616139
38626133356364613562393664643563346539366364636332613162663337356232333735393431
30343635393462356431646336636663333735343164616261343836363366616162613563613066
66333034613234626431356536323832393466363135653231336238356334353638613838626430
63636630313533363563376161663637353362383431663130646666646433353864373736613662
62343666633862643839666532656132653939663437373164393536653739376265303130353636
62616538326330333136626238306133363634326365366637363961333635356133613564373131
64626139656633663065353862343135393233333231386166346532656534623361623061336434
37616565626134333863376532393861376132323434656433613731613834633963386635353336
39653263346637303836663763653264396139383363616461393333333362616332663863363834
61613832326466646133626337663364333566326633313664613236346135653332373035313034
62356530313065393737393634313166313039616635363365633031336434396463326462316236
62353838636533303664663132353838636632353733316639643964666139383539333761663531
37366530373165653063303032383461326535613336343635626538373635356266396666346133
61383434323565306438356634646338666232363238393932353365363461376130323363363236
34643862653937353461383265663933646264373365623465313666643662633334366437646434
34343332613832366235663563353435323738356339383338333361383561336366376238393237
38656265663164376666616366623062393530366261623361383365376235643035353838313235
32396430376139313430316439333539343266393965353030636638656661316137313437663832
64366661323865383262323036613230316233666566386133363633303931323464663238323861
62333132346165353830653062353763306232366563323430383933653163373562326536393362
66353931376262383931613931303034356537363137366235643430323465623162363031373034
64653563666533363062333831336463376530306639616631303266386136666233653638653732
31313537393838333730303235363661326333646531653935633935373362303732653565656438
36626330623063373832333739643666396135653838643164376264393863646433353036643731
34623636623366353466333237373265323936643134613230326565303663306431373634356334
37613732393262626135306632623336613364323632316636623037656538313236666562633438
37306361333130376538366232393637646263656239303431623963626265386634313735373162
64393733303132383464386330626135336237303563326238633437346164333738646431333730
62616533363638643261306565373835303832313539656564386132393863373039653938616261
36343031356361336563316230343433633033353130373933313361326164633765316433616162
62356338393634653330623933313433343630386264396337373532376335316362333164363963
363663666365336564663232363462613162
34313539653264336537326165616161313931303664633032373566626264643439393136386230
6330353962336634623963336535333130626662336561650a303864333966333336376661356139
35303531343330356331356166666666343739636564353039313637663066356135623630396236
6434663137386232300a323334313332373630366133393530313438623733666333623437666539
65376166643436303661343763383166616662653137636539623435653632623433396465616363
33336431363266653138366564343862626634373838316439313339313961323437656435623635
37653534376262656130373734353335663764386633646436396335616437633636376462343861
38343430363733316166353032343164313333663865356335393634656335373636346565653233
63386535366533303736623463623830363166646530666631643730303265396163353538656662
34363964356665666464336636373535613639343535633361383064623065643230303066303661
35333666353331363031353732643233613439666539373539343437336362656132373634663636
30383039303266663961666662613730646664386266356338366335633663666162343338363263
63323531613735363333613637666530323830346135653839353733306561396239373734313530
61616233313264323264396230393163303766666665656330636636306661303838333265383535
63383330363331663038643735653266333233613666393161636634396365663832653736306437
39636230336336613863623562376134616234323434653061656534383132353038333966663631
36666562623234303130373661636136336538386163353230383830303438336435346432623761
36636263306564323039356165623835363730643463343065366436323235616639376363363037
38623165623635363239366361616337663932653734383162376363396533373563643439633632
36306564336165363035386663323366343636383366393366373732393634356236626535356333
38383633316362396133346631303234363366666664343137633765353231306534653837323035
65333762383164663433356438333264323631373561353762646265386630616536633833306565
32336635623036666131613634333332393037643063373561303938313762666262353564303039
31333731396661373865313862633732313864306131303936333638323965613831323034303130
39393864663136383430626137323736313132303030326131616463653635383262353731653034
65643437323434626637313333666538613039633635333231386433363963653432376164383364
34376437386166363335373964666631393230383038333137636439643936393866356537393535
35306135313532363462653734633162363236356436386161656164666261393236393162353865
38613964613434636334663361396362396163623533623166306261366130633962653131386365
65626464663736326365376166633538303439326561643362633163626330643265393630303163
62383835623639663838663934663030383363646339663632666364613830373263313437303964
37343664356135663361323539663562323265373163303035633463326162363462636131363436
31343764313537666661656631643263353239616563636361633561313966663932616163313932
66363837656538373337653737653061356237383436643964653230333263313063333033663866
61613634363463363232663765646438653266386166623431363932383931396339633665633430
62306437633438393136643930653939623734643162353961313831613337646435656436353436
30396265643732636337303233623931643361663032383335333431623063393731633764636166
38663465366537636539376661643237623936333565383666333163363066366532633965346463
38653265373262663039353433663134373361663535336633383566303462393663623432653836
64323838343432343061323338353633613930613463383465633465313436343932366163313361
32356431353434353434306462306134643332326363353462666561663035356530376263653831
30616533323666363161653231663835663532336236663034316364333438336130383537346633
65656565643363303036396439373963623338626461366234623233626231323534616130623537
66323666346439333763646635643635663538633361356637646565353234316264306339373765
37356236323763383761323637306163613933623661353262643362636330393362646236386563
38323236666633306336393839396439303536643933393331333363626533373636356339623235
66643436343736383136656630356139653537356632343838636364306461326539373932383430
66343736333261316363316230623336313366303963366134666533626363353937373434383965
65363737626534363030386461333261363736373230323437303636353030373335366266643566
34313863363864306331306130626135623265643935376130303566636432646532356438613635
36353766373434323638626330313030333737346262653833643735306432623836323834663638
34646130623363613763346163363435643561336332663865623563343666616338616134336361
31313731646434666263303136613338613637613530303932646561616138393032343838623766
35633163366463346663656331386539376263646264343466366466663664643661383238326138
38646231616133373038343636383733643661366131646335623564623663326537373039353535
36643062623063663131363765666265303231333332333535316634336262306437633236323961
66653263613836373235363166326337393762346534636330633931356265613765363336386162
61393630636136313630613363383138333939313231396332353132313139323362386162613364
63633261313965323966396635623334333633353963663263666433616632613463353231386238
61333439613839353431613637633465616338363334333962666464396563356266323538373761
64343436636138663934306130336663633665356465303064363637316332656432666639633330
39383664616536383265303265663437303438393833663066343735616261653736346230663663
34663563653862316335326661663264333138613430643934303334343838623934356431313264
61393166616239613131636131643762313563623137633966326362326664346438366564306130
30663161306462383836646436316138373431636339633438343439633633663735336433356232
36373437323031303637636231646262343133646632633561393339303835326336656533613562
36616530623530386238623262393537626632376637663232336138353232396333383837303362
36623538333432396439306261356663383163653665393530313434616137626230356463333434
30383861363164343866326264366135346166633936313834636162303764613735383565663264
30616264643535353730396435633863646634616332303337363230366666373563656534383661
34613835346565393730353165663264656661623930623361383465366336383933626162393530
39353535613237313064613537383564323164323337313039393637396534383563373637373730
66653539303963623034333862613539613663323238333765646138656464386535336334626437
35626465623864376539333964316533326235626265346438333737633738393532323162306430
66353633386337626462643466343333353130356663363766353161333662323830643261376139
32616465326135373037636265306436653630646164323365636166356362353634343036623035
35303136373235313431613932666230353034396334336561333732353762656434633037666664
31306438386635613038623662336137336430653434383730653161383239376466326232323163
66653738363030626231383930303335333663623837366464633764333461636461303131393966
32303035376661623738323032346638613261313963626130386464383032303334383735396564
63326633376139316436393236643066656631396134393962366363346233666232393434626134
31653933383631613064303563656665383834623662306137303861623063663437636335326430
62306630393938323832613830353230313136383834333832343366646632366634393632383539
61373531653862623261633766613531346263343030373733383465353233316162656566386264
35313834333739393064303730306262663032376335663032613233343131336662623065346231
37653164633632396635363434623936346135616531353536323961336662646334666335306137
38343037303337363966663934663733303364323134613633313566346161376661383032393832
35363531316431303937323761323234666436313661623833323235373539393134346261666533
32396665383961316166633836656562623665656134353762303238373633376333356664666539
33356430613663366162316663623735646434656261613835363835343935323765626335326139
34636439313466363438343862313636303163376635383361633338363664623830613837616464
34306636346438313437613430306466383166373431353435656166643638626236373533393939
62366538353262383239396236653664613664626236326531386536643433313361393065316562
37303435333231313434653939313264613031343266616537383464356334333137646132396536
30623238346662323163656365323933373366323530306530613032363861643037393332626531
30353838393263306137633564376430323038313162626633623238353136653032653936303863
33373135656434316466663363616138623734313063666632393265343532333433303731373239
30393635333465313735363030386634323635393335383532326138346538633264386163623463
34396336366638306633633732363162633336353962303261346439396231366337653633653161
34383732333530366136366334396630303533336165653333326465306439313233373335326237
30663331643839663534666338616466323633636364363663353462613632353764353931663164
39306462623434653035396534663232326533643032343139663237366235653265393164373735
30626435626235343730366265633935663463663435633137646138393765323738633162623239
65666666353339656636633765313164306339383135623633643763396530643061383764373364
38616233613562353831343838343830323130646662363061316534346564336631343639623161
38666338346330643537366631313165366632643932323131613836303362383733633165653762
64383539303139386337323931623531373461343737303236396534346566363338306138393334
62363961386234326539663433646530663233306365613662633737376237393838306361343365
31623538353362663830646436376236333161656238303332303339353531613461313839643239
65613230373035336434363632633735643063646363656133326630336461313035633662613763
65333665323764306535656137343034656165366530386166353964636338653532613332633437
64323665333335386661376437303539336534393865353262623366323762326435313262626234
37323433333138363837613034616662383362636462616134393431303737306166646233346362
33633536636537633230353039623562636635396138366131366337613131323334356139346433
62393564656635663836383164343562303637303533376665383638343238653939663962303535
61383232316264323434366530623635623637623062333235646436646531643261633264393461
36333766356434633532363536353734383866656461613338633234363966313661333537613439
37343236396535666661656634326439633539303339616563643465613732343933393131623038
63353231633633356563373438396335636439326136363463366663646565313532303230313836
33613734323538316534386531616233646431623435326338366339386431376363656439326535
39373065386463353435396466323433343436306639303266323431653037336463316532376533
39656365303166306430646664346539376366343332633837303030376561623966393732393466
65353563346234633965623036636264386239336537656237313433633932323063636239616561
34323261373938333462623862393063333963306333616530656232646461363132323932663231
65656361326139323030326332613166303461326236383432323761663061353134633736353665
39643932363538376163613063316533346530646139626536356663633464636235353035653362
61313838363065623365666538643562356336373539343237366161316130373461306362353133
37343965666436643633626461613738303738313838326265373164373464643037363861643730
30326431393865373362363836333631393039313938343834366237653961353163326665306262
34643836653434313838303035623961613036656630666266366330313031386338326563663833
64323535663438313865306539343936393864376263393532336538316530663839643161346233
65383831316566373734636462396161323630376434666430653235373238303932616662666437
31373532353339366534316463623237313835366164663630343561623861383263626365663566
66383034613939363736356262336336356363313332363466653534653336353964313831363139
34626436623231306434393464376639303462356132636630373762366135613935363033623137
39643036366263353139623539666130333163616562353239353731623534346635653239396636
39363636346234356465383365356462333430366265306464666666393033656638393930626661
36616365393637316231656239336135333664346139373163303231363266393562626364346561
36333738373738643136653465353331316561646162383230666133636135646330636363653061
35623234303233326531356537616131356533386334623938303462613337323930623566343664
34323831616636393264643765653262316434623635373733623139396131636366353033653263
66393361653766623161343935626234336163363765313339653266343837313731653839643066
36633861663130346635343863646166393238333165316365333230376433333439613731333461
37353035323931306462646465323066333463333236353665303664393461353030343963346132
32396237626335313831616662383165333439393739353865623631333630363432633366646263
32633435366461656535323230613739323634386536666132633935313532663763353963343065
61616134333630633333616639333062663636326237366265326264613863353537323232373165
32663964313736313031376662663631663635393731333264613566336661623030616235333163
31343865333735633933373933303030393632656435333032373730663866343736626663623136
62643566356665356234306134653037383638303064316138313638653336616364393934623862
38613864313962633335653165363437383631366531613731633339313562366364306164386430
34326133643436616537336132306634613461353963306664313531633564653134383330336537
64393331346566313966626238663733646565343761353563623461663662336331656634323964
34323965326638363038316233623431656233346165373136343532316635326561356265336232
63396563383765333736356638363261396634303730383136663566383135303331373534313766
66363335356265396164326438393862613333663936666230316133396563376535663365633061
35323665373233656631633038343631356233633934666161633766306331373537646231306437
32623965656139373835333238343565643635306437656262623334316633646361623262386435
32663031323338313339386663656363316164353666346237316137313562623838326436383862
35616663633433613064613264363637396632333734326231343830633537336364346336316461
3833

View file

@ -0,0 +1,59 @@
# `forgejo_runner`
Installs and runs a Forgejo Actions runner, registers it with the Forgejo
instance, and keeps a health check on a systemd timer.
Converted from `deploy_forgejo_runner_playbook.yml` (409 lines) under Plan 6.
The playbook is now 16 lines.
## Phases
`tasks/main.yml` imports five files in order:
| | |
|---|---|
| `prerequisites.yml` | Docker must be present |
| `install.yml` | binary, system user, working directory |
| `configure.yml` | config file, registration with the instance |
| `service.yml` | systemd unit, start, assert it came up |
| `healthcheck.yml` | check script, unit, timer |
`import_tasks`, not `include_tasks` — static imports are visible to
`--list-tasks`, which is how the conversion was verified against the playbook it
replaced.
## Monitoring: one variable, no product knowledge
This role contains **nothing specific to any monitoring system**. What used to
be here — an ~80-line embedded Python script creating monitors over the Uptime
Kuma API, a `/tmp` credentials file, token extraction, a systemd `Environment=`
rewrite, and 8 `when: uptime_kuma_enabled` guards — is gone.
What remains answers the actual question, *is this service healthy*, and records
it two ways:
- **the exit code**, which systemd keeps: `systemctl is-failed
forgejo-runner-healthcheck.service` is a complete answer with no monitoring
system involved at all;
- **a log file** at `{{ healthcheck_log_file }}`.
To report health somewhere, set one variable:
```yaml
healthcheck_push_url: "https://example/api/push/TOKEN"
```
Any endpoint accepting an HTTP ping works. Empty (the default) means check, log,
exit honestly, report nowhere — which is also the right setting for a *pull*-based
monitor like Prometheus' textfile collector, since that reads unit state instead.
The push URL is a credential (anyone holding it can forge an "up"), so callers
pass it from the vault rather than committing it.
## One behaviour change, deliberate
`Assert runner is running` used to be guarded by `uptime_kuma_enabled`, so it
never ran. It is not a monitoring task — it is the deployment checking its own
work — and the deprecation banner swept it up by mistake. It is ungated here,
which means a runner that fails to start now fails the play instead of
deploying "successfully" in silence.

View file

@ -0,0 +1,40 @@
---
# Binary
forgejo_runner_version: "6.3.1"
forgejo_runner_arch: "linux-amd64"
forgejo_runner_url: "https://code.forgejo.org/forgejo/runner/releases/download/v{{ forgejo_runner_version }}/forgejo-runner-{{ forgejo_runner_version }}-{{ forgejo_runner_arch }}"
forgejo_runner_bin_path: "/usr/local/bin/forgejo-runner"
# Runtime
forgejo_runner_user: "runner"
forgejo_runner_dir: "/opt/forgejo-runner"
forgejo_runner_config_path: "{{ forgejo_runner_dir }}/config.yml"
forgejo_runner_labels: "docker:docker://node:20-bookworm,ubuntu-latest:docker://node:20-bookworm,ubuntu-22.04:docker://node:20-bookworm,ubuntu-24.04:docker://node:20-bookworm"
# The Forgejo instance this runner registers with.
forgejo_instance_url: "https://forgejo.contrapeso.xyz"
# forgejo_runner_registration_token comes from the vault.
# --- Health check -----------------------------------------------------------
# The check answers "is this service healthy" and records the answer two ways:
# a log file, and its own exit code. The exit code is the durable artefact —
# systemd stores it, so `systemctl is-failed forgejo-runner-healthcheck.service`
# answers the question with no monitoring system involved at all.
healthcheck_interval_seconds: 60
healthcheck_timeout_seconds: 90
healthcheck_retries: 1
healthcheck_script_dir: /opt/forgejo-runner-healthcheck
healthcheck_script_path: "{{ healthcheck_script_dir }}/forgejo_runner_healthcheck.sh"
healthcheck_log_file: "{{ healthcheck_script_dir }}/forgejo_runner_healthcheck.log"
healthcheck_service_name: forgejo-runner-healthcheck
# WHERE TO REPORT HEALTH — the one place to plug in monitoring.
#
# Empty means "check, log, exit honestly, report nowhere". Set it to any URL
# that accepts an HTTP ping and the check will report there. Nothing in this
# role is specific to a particular monitoring product: the Uptime Kuma API
# calls, monitor creation and token handling that used to live here are gone.
#
# A pull-based monitor (Prometheus node_exporter textfile, say) needs this left
# empty — it reads the systemd unit state instead.
healthcheck_push_url: ""

View file

@ -0,0 +1,43 @@
---
- name: Check if config already exists
stat:
path: "{{ forgejo_runner_config_path }}"
register: config_stat
- name: Generate default config
shell: "{{ forgejo_runner_bin_path }} generate-config > {{ forgejo_runner_config_path }}"
args:
chdir: "{{ forgejo_runner_dir }}"
when: not config_stat.stat.exists
- name: Set config file ownership
file:
path: "{{ forgejo_runner_config_path }}"
owner: "{{ forgejo_runner_user }}"
group: "{{ forgejo_runner_user }}"
when: not config_stat.stat.exists
# ── 6. Register runner ─────────────────────────────────────────────
- name: Check if runner is already registered
stat:
path: "{{ forgejo_runner_dir }}/.runner"
register: runner_stat
- name: Register runner with Forgejo instance
command: >
{{ forgejo_runner_bin_path }} register --no-interactive
--instance {{ forgejo_instance_url }}
--token {{ forgejo_runner_registration_token }}
--name forgejo-runner-box
--labels "{{ forgejo_runner_labels }}"
args:
chdir: "{{ forgejo_runner_dir }}"
when: not runner_stat.stat.exists
- name: Set runner registration file ownership
file:
path: "{{ forgejo_runner_dir }}/.runner"
owner: "{{ forgejo_runner_user }}"
group: "{{ forgejo_runner_user }}"
when: not runner_stat.stat.exists

View file

@ -0,0 +1,73 @@
---
# Everything here answers "is the service healthy" and records the answer.
# The Uptime Kuma specifics that used to surround it — an embedded Python script
# that created monitors over the API, a /tmp credentials file, token extraction,
# and a systemd Environment= rewrite — are gone. What reports where is now one
# variable, healthcheck_push_url. See the role README.
- name: Create healthcheck script directory
ansible.builtin.file:
path: "{{ healthcheck_script_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Create forgejo-runner healthcheck script
ansible.builtin.template:
src: healthcheck.sh.j2
dest: "{{ healthcheck_script_path }}"
owner: root
group: root
mode: '0755'
validate: "bash -n %s"
- name: Create healthcheck systemd service
ansible.builtin.template:
src: healthcheck.service.j2
dest: "/etc/systemd/system/{{ healthcheck_service_name }}.service"
owner: root
group: root
mode: '0644'
- name: Create healthcheck systemd timer
ansible.builtin.template:
src: healthcheck.timer.j2
dest: "/etc/systemd/system/{{ healthcheck_service_name }}.timer"
owner: root
group: root
mode: '0644'
- name: Reload systemd for healthcheck units
systemd:
daemon_reload: yes
- name: Enable and start healthcheck timer
systemd:
name: "{{ healthcheck_service_name }}.timer"
enabled: yes
state: started
- name: Test healthcheck script
command: "{{ healthcheck_script_path }}"
register: healthcheck_test
changed_when: false
- name: Verify healthcheck script works
assert:
that:
- healthcheck_test.rc == 0
fail_msg: "Healthcheck script failed to execute properly"
- name: Display deployment summary
debug:
msg: |
Forgejo Runner deployed successfully!
Runner Name: forgejo-runner-box
Instance: {{ forgejo_instance_url }}
Working Directory: {{ forgejo_runner_dir }}
Service: forgejo-runner.service ({{ runner_active.stdout }})
Healthcheck Monitor: {{ healthcheck_service_name }}
Healthcheck Interval: Every {{ healthcheck_interval_seconds }}s
Reporting to: {{ healthcheck_push_url | default('', true) | regex_replace('/api/push/.*', '/api/push/***') | default('(nowhere - set healthcheck_push_url)', true) }}

View file

@ -0,0 +1,27 @@
---
- name: Download forgejo-runner binary
get_url:
url: "{{ forgejo_runner_url }}"
dest: "{{ forgejo_runner_bin_path }}"
mode: '0755'
# ── 3. Create runner system user ───────────────────────────────────
- name: Create runner system user
user:
name: "{{ forgejo_runner_user }}"
system: yes
shell: /usr/sbin/nologin
home: "{{ forgejo_runner_dir }}"
create_home: no
groups: docker
append: yes
comment: 'Forgejo Runner'
# ── 4. Create working directory ────────────────────────────────────
- name: Create forgejo-runner working directory
file:
path: "{{ forgejo_runner_dir }}"
state: directory
owner: "{{ forgejo_runner_user }}"
group: "{{ forgejo_runner_user }}"
mode: '0750'

View file

@ -0,0 +1,9 @@
---
# import_tasks, not include_tasks: these are unconditional phases, and static
# imports are visible to `--list-tasks`. That matters because the task list is
# how this refactor was verified against the playbook it replaced.
- ansible.builtin.import_tasks: prerequisites.yml
- ansible.builtin.import_tasks: install.yml
- ansible.builtin.import_tasks: configure.yml
- ansible.builtin.import_tasks: service.yml
- ansible.builtin.import_tasks: healthcheck.yml

View file

@ -0,0 +1,12 @@
---
- name: Check if Docker is installed
command: docker --version
register: docker_check
changed_when: false
failed_when: docker_check.rc != 0
- name: Fail if Docker is not available
assert:
that:
- docker_check.rc == 0
fail_msg: "Docker is required for forgejo-runner but is not installed"

View file

@ -0,0 +1,33 @@
---
- name: Create forgejo-runner systemd service
ansible.builtin.template:
src: forgejo-runner.service.j2
dest: /etc/systemd/system/forgejo-runner.service
owner: root
group: root
mode: '0644'
- name: Reload systemd
systemd:
daemon_reload: yes
- name: Enable and start forgejo-runner service
systemd:
name: forgejo-runner
enabled: yes
state: started
- name: Verify forgejo-runner is active
command: systemctl is-active forgejo-runner
register: runner_active
changed_when: false
# Ungated on purpose. This was previously guarded by `uptime_kuma_enabled`, but
# it is not a monitoring task — it is the deployment asserting its own success.
# The deprecation banner swept it up along with the Kuma plumbing, which meant a
# broken runner deployed "successfully" and silently.
- name: Assert runner is running
assert:
that:
- runner_active.stdout == "active"
fail_msg: "forgejo-runner service is not active: {{ runner_active.stdout }}"

View file

@ -0,0 +1,17 @@
[Unit]
Description=Forgejo Runner
Documentation=https://forgejo.org/docs/latest/admin/actions/
After=docker.service
Requires=docker.service
[Service]
Type=simple
User={{ forgejo_runner_user }}
Group={{ forgejo_runner_user }}
WorkingDirectory={{ forgejo_runner_dir }}
ExecStart={{ forgejo_runner_bin_path }} daemon --config {{ forgejo_runner_config_path }}
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,13 @@
[Unit]
Description=Forgejo Runner Healthcheck
After=network.target
[Service]
Type=oneshot
ExecStart={{ healthcheck_script_path }}
User=root
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,43 @@
#!/bin/bash
# Forgejo Runner healthcheck — managed by Ansible (roles/forgejo_runner)
#
# Answers "is forgejo-runner healthy" and records it two ways: this log, and the
# exit code. The exit code is the durable artefact — systemd keeps it, so
# systemctl is-failed {{ healthcheck_service_name }}.service
# answers the question with no monitoring system involved.
#
# Reporting is optional and generic: if a push URL is configured it also pings
# it. Nothing here knows or cares which monitoring product is on the other end.
LOG_FILE="{{ healthcheck_log_file }}"
PUSH_URL="{{ healthcheck_push_url }}"
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}
main() {
if ! systemctl is-active --quiet forgejo-runner; then
log_message "ERROR: forgejo-runner is not active"
exit 1
fi
if [ -z "$PUSH_URL" ]; then
# Healthy, and nothing to report to. Not an error: the exit code below
# is still a complete answer for anything reading unit state.
log_message "forgejo-runner is active (no push URL configured)"
exit 0
fi
log_message "forgejo-runner is active, sending ping"
response=$(curl -s -w "\n%{http_code}" "$PUSH_URL?status=up&msg=forgejo-runner%20is%20active" 2>&1)
http_code=$(echo "$response" | tail -n1)
if [ "$http_code" = "200" ] || [ "$http_code" = "201" ]; then
log_message "Ping sent successfully (HTTP $http_code)"
else
log_message "ERROR: Failed to send ping (HTTP $http_code)"
exit 1
fi
}
main

View file

@ -0,0 +1,11 @@
[Unit]
Description=Run Forgejo Runner Healthcheck every minute
Requires={{ healthcheck_service_name }}.service
[Timer]
OnBootSec=30sec
OnUnitActiveSec={{ healthcheck_interval_seconds }}sec
Persistent=true
[Install]
WantedBy=timers.target

View file

@ -1,3 +1,4 @@
---
- name: Install Forgejo Runner on Debian 13
hosts: ci_runner
become: yes
@ -5,405 +6,11 @@
- ../../infra_vars.yml
- ../../services_config.yml
- ../../infra_secrets.yml
- ./forgejo_runner_vars.yml
vars:
uptime_kuma_api_url: "https://{{ subdomains.uptime_kuma }}.{{ root_domain }}"
ntfy_topic: "{{ service_settings.ntfy.topic }}"
healthcheck_interval_seconds: 60
healthcheck_timeout_seconds: 90
healthcheck_retries: 1
healthcheck_script_dir: /opt/forgejo-runner-healthcheck
healthcheck_script_path: "{{ healthcheck_script_dir }}/forgejo_runner_healthcheck.sh"
healthcheck_log_file: "{{ healthcheck_script_dir }}/forgejo_runner_healthcheck.log"
healthcheck_service_name: forgejo-runner-healthcheck
tasks:
# ── 1. Assert Docker is available ──────────────────────────────────
- name: Check if Docker is installed
command: docker --version
register: docker_check
changed_when: false
failed_when: docker_check.rc != 0
- name: Fail if Docker is not available
assert:
that:
- docker_check.rc == 0
fail_msg: >
Docker is not installed or not in PATH.
Please install Docker before running this playbook.
# ── 2. Download forgejo-runner binary ──────────────────────────────
- name: Download forgejo-runner binary
get_url:
url: "{{ forgejo_runner_url }}"
dest: "{{ forgejo_runner_bin_path }}"
mode: '0755'
# ── 3. Create runner system user ───────────────────────────────────
- name: Create runner system user
user:
name: "{{ forgejo_runner_user }}"
system: yes
shell: /usr/sbin/nologin
home: "{{ forgejo_runner_dir }}"
create_home: no
groups: docker
append: yes
comment: 'Forgejo Runner'
# ── 4. Create working directory ────────────────────────────────────
- name: Create forgejo-runner working directory
file:
path: "{{ forgejo_runner_dir }}"
state: directory
owner: "{{ forgejo_runner_user }}"
group: "{{ forgejo_runner_user }}"
mode: '0750'
# ── 5. Generate default config ─────────────────────────────────────
- name: Check if config already exists
stat:
path: "{{ forgejo_runner_config_path }}"
register: config_stat
- name: Generate default config
shell: "{{ forgejo_runner_bin_path }} generate-config > {{ forgejo_runner_config_path }}"
args:
chdir: "{{ forgejo_runner_dir }}"
when: not config_stat.stat.exists
- name: Set config file ownership
file:
path: "{{ forgejo_runner_config_path }}"
owner: "{{ forgejo_runner_user }}"
group: "{{ forgejo_runner_user }}"
when: not config_stat.stat.exists
# ── 6. Register runner ─────────────────────────────────────────────
- name: Check if runner is already registered
stat:
path: "{{ forgejo_runner_dir }}/.runner"
register: runner_stat
- name: Register runner with Forgejo instance
command: >
{{ forgejo_runner_bin_path }} register --no-interactive
--instance {{ forgejo_instance_url }}
--token {{ forgejo_runner_registration_token }}
--name forgejo-runner-box
--labels "{{ forgejo_runner_labels }}"
args:
chdir: "{{ forgejo_runner_dir }}"
when: not runner_stat.stat.exists
- name: Set runner registration file ownership
file:
path: "{{ forgejo_runner_dir }}/.runner"
owner: "{{ forgejo_runner_user }}"
group: "{{ forgejo_runner_user }}"
when: not runner_stat.stat.exists
# ── 7. Create systemd service ──────────────────────────────────────
- name: Create forgejo-runner systemd service
copy:
dest: /etc/systemd/system/forgejo-runner.service
content: |
[Unit]
Description=Forgejo Runner
Documentation=https://forgejo.org/docs/latest/admin/actions/
After=docker.service
Requires=docker.service
[Service]
Type=simple
User={{ forgejo_runner_user }}
Group={{ forgejo_runner_user }}
WorkingDirectory={{ forgejo_runner_dir }}
ExecStart={{ forgejo_runner_bin_path }} daemon --config {{ forgejo_runner_config_path }}
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
owner: root
group: root
mode: '0644'
# ── 8. Reload systemd, enable and start ────────────────────────────
- name: Reload systemd
systemd:
daemon_reload: yes
- name: Enable and start forgejo-runner service
systemd:
name: forgejo-runner
enabled: yes
state: started
# ── 9. Verify runner is active ─────────────────────────────────────
- name: Verify forgejo-runner is active
command: systemctl is-active forgejo-runner
register: runner_active
changed_when: false
# ═════════════════════════════════════════════════════════════════════════
# DEPRECATED — Uptime Kuma was decommissioned on 2026-09-11.
#
# Every task below is inert: uptime_kuma_enabled is false in
# group_vars/all/main.yml, so they all skip and the deployment above still
# runs normally. Kept because the health-check logic is the durable part —
# when a replacement exists, rewire the push transport and flip the flag.
#
# What was being monitored: archive/uptime_kuma/MONITORS.md
# ═════════════════════════════════════════════════════════════════════════
- name: Assert runner is running
when: uptime_kuma_enabled | default(false)
assert:
that:
- runner_active.stdout == "active"
fail_msg: "forgejo-runner service is not active: {{ runner_active.stdout }}"
# ── 10. Set up Uptime Kuma push monitor ────────────────────────────
- name: Create Uptime Kuma push monitor setup script
when: uptime_kuma_enabled | default(false)
copy:
dest: /tmp/setup_forgejo_runner_monitor.py
content: |
#!/usr/bin/env python3
import sys
import json
from uptime_kuma_api import UptimeKumaApi
def main():
api_url = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
group_name = sys.argv[4]
monitor_name = sys.argv[5]
monitor_description = sys.argv[6]
interval = int(sys.argv[7])
retries = int(sys.argv[8])
ntfy_topic = sys.argv[9] if len(sys.argv) > 9 else "alerts"
api = UptimeKumaApi(api_url, timeout=60, wait_events=2.0)
api.login(username, password)
# Get all monitors
monitors = api.get_monitors()
# Get all notifications and find ntfy notification
notifications = api.get_notifications()
ntfy_notification = next((n for n in notifications if n.get('name') == f'ntfy ({ntfy_topic})'), None)
notification_id_list = {}
if ntfy_notification:
notification_id_list[ntfy_notification['id']] = True
# Find or create group
group = next((m for m in monitors if m.get('name') == group_name and m.get('type') == 'group'), None)
if not group:
group_result = api.add_monitor(type='group', name=group_name)
# Refresh to get the full group object with id
monitors = api.get_monitors()
group = next((m for m in monitors if m.get('name') == group_name and m.get('type') == 'group'), None)
# Find or create/update push monitor
existing_monitor = next((m for m in monitors if m.get('name') == monitor_name), None)
monitor_data = {
'type': 'push',
'name': monitor_name,
'parent': group['id'],
'interval': interval,
'upsideDown': False,
'maxretries': retries,
'description': monitor_description,
'notificationIDList': notification_id_list
}
if existing_monitor:
monitor = api.edit_monitor(existing_monitor['id'], **monitor_data)
# Refresh to get the full monitor object with pushToken
monitors = api.get_monitors()
monitor = next((m for m in monitors if m.get('name') == monitor_name), None)
else:
monitor_result = api.add_monitor(**monitor_data)
# Refresh to get the full monitor object with pushToken
monitors = api.get_monitors()
monitor = next((m for m in monitors if m.get('name') == monitor_name), None)
result = {
'monitor_id': monitor['id'],
'push_token': monitor['pushToken'],
'group_name': group_name,
'group_id': group['id'],
'monitor_name': monitor_name
}
print(json.dumps(result))
api.disconnect()
if __name__ == '__main__':
main()
mode: '0755'
delegate_to: localhost
become: no
- name: Run Uptime Kuma push monitor setup
when: uptime_kuma_enabled | default(false)
command: >
{{ ansible_playbook_python }}
/tmp/setup_forgejo_runner_monitor.py
"{{ uptime_kuma_api_url }}"
"{{ uptime_kuma_username }}"
"{{ uptime_kuma_password }}"
"services"
"forgejo-runner-healthcheck"
"Forgejo Runner healthcheck - ping every {{ healthcheck_interval_seconds }}s"
"{{ healthcheck_timeout_seconds }}"
"{{ healthcheck_retries }}"
"{{ ntfy_topic }}"
register: monitor_setup_result
delegate_to: localhost
become: no
changed_when: false
- name: Parse monitor setup result
when: uptime_kuma_enabled | default(false)
set_fact:
monitor_info_parsed: "{{ monitor_setup_result.stdout | from_json }}"
- name: Set push URL
when: uptime_kuma_enabled | default(false)
set_fact:
uptime_kuma_push_url: "{{ uptime_kuma_api_url }}/api/push/{{ monitor_info_parsed.push_token }}"
- name: Create healthcheck script directory
file:
path: "{{ healthcheck_script_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Create forgejo-runner healthcheck script
when: uptime_kuma_enabled | default(false)
copy:
dest: "{{ healthcheck_script_path }}"
content: |
#!/bin/bash
# Forgejo Runner Healthcheck Script
# Checks if forgejo-runner is active and pings Uptime Kuma on success
LOG_FILE="{{ healthcheck_log_file }}"
UPTIME_KUMA_URL="{{ uptime_kuma_push_url }}"
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}
main() {
if systemctl is-active --quiet forgejo-runner; then
log_message "forgejo-runner is active, sending ping"
response=$(curl -s -w "\n%{http_code}" "$UPTIME_KUMA_URL?status=up&msg=forgejo-runner%20is%20active" 2>&1)
http_code=$(echo "$response" | tail -n1)
if [ "$http_code" = "200" ] || [ "$http_code" = "201" ]; then
log_message "Ping sent successfully (HTTP $http_code)"
else
log_message "ERROR: Failed to send ping (HTTP $http_code)"
exit 1
fi
else
log_message "ERROR: forgejo-runner is not active"
exit 1
fi
}
main
owner: root
group: root
mode: '0755'
- name: Create healthcheck systemd service
copy:
dest: "/etc/systemd/system/{{ healthcheck_service_name }}.service"
content: |
[Unit]
Description=Forgejo Runner Healthcheck
After=network.target
[Service]
Type=oneshot
ExecStart={{ healthcheck_script_path }}
User=root
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
owner: root
group: root
mode: '0644'
- name: Create healthcheck systemd timer
copy:
dest: "/etc/systemd/system/{{ healthcheck_service_name }}.timer"
content: |
[Unit]
Description=Run Forgejo Runner Healthcheck every minute
Requires={{ healthcheck_service_name }}.service
[Timer]
OnBootSec=30sec
OnUnitActiveSec={{ healthcheck_interval_seconds }}sec
Persistent=true
[Install]
WantedBy=timers.target
owner: root
group: root
mode: '0644'
- name: Reload systemd for healthcheck units
systemd:
daemon_reload: yes
- name: Enable and start healthcheck timer
systemd:
name: "{{ healthcheck_service_name }}.timer"
enabled: yes
state: started
- name: Test healthcheck script
command: "{{ healthcheck_script_path }}"
register: healthcheck_test
changed_when: false
- name: Verify healthcheck script works
assert:
that:
- healthcheck_test.rc == 0
fail_msg: "Healthcheck script failed to execute properly"
- name: Display deployment summary
debug:
msg: |
Forgejo Runner deployed successfully!
Runner Name: forgejo-runner-box
Instance: {{ forgejo_instance_url }}
Working Directory: {{ forgejo_runner_dir }}
Service: forgejo-runner.service ({{ runner_active.stdout }})
Healthcheck Monitor: forgejo-runner-healthcheck
Healthcheck Interval: Every {{ healthcheck_interval_seconds }}s
Timeout: {{ healthcheck_timeout_seconds }}s
- name: Clean up temporary monitor setup script
when: uptime_kuma_enabled | default(false)
file:
path: /tmp/setup_forgejo_runner_monitor.py
state: absent
delegate_to: localhost
become: no
# Preserves the push URL this host has been reporting to all along, so the
# move to a role changes no behaviour. The role itself knows nothing about
# Uptime Kuma — this is just "a URL that accepts a ping", and whatever
# replaces it sets the same variable.
healthcheck_push_url: "{{ healthcheck_push_urls.forgejo_runner | default('') }}"
roles:
- forgejo_runner

View file

@ -1,9 +0,0 @@
forgejo_runner_version: "6.3.1"
forgejo_runner_arch: "linux-amd64"
forgejo_runner_url: "https://code.forgejo.org/forgejo/runner/releases/download/v{{ forgejo_runner_version }}/forgejo-runner-{{ forgejo_runner_version }}-{{ forgejo_runner_arch }}"
forgejo_runner_bin_path: "/usr/local/bin/forgejo-runner"
forgejo_runner_user: "runner"
forgejo_runner_dir: "/opt/forgejo-runner"
forgejo_runner_config_path: "{{ forgejo_runner_dir }}/config.yml"
forgejo_runner_labels: "docker:docker://node:20-bookworm,ubuntu-latest:docker://node:20-bookworm,ubuntu-22.04:docker://node:20-bookworm,ubuntu-24.04:docker://node:20-bookworm"
forgejo_instance_url: "https://forgejo.contrapeso.xyz"