Trh (plánovaný)
Voliteľný trh, na ktorom jedno zariadenie predáva voľné úložisko alebo výpočtový výkon a iný ho kupuje. Platby idú cez Stripe Connect a edge si ponecháva 4 % na pokrytie svojich prevádzkových nákladov.
Zatiaľ nie je otvorený. Kód je hotový od začiatku do konca: routy
registrara /market/*, Stripe gate, relay v lososd aj panel v admin UI.
Platforma Stripe Connect však potrebuje za sebou registrovanú firmu a tá
zatiaľ neexistuje. Kým nebude, admin UI zobrazuje kartu Trh sivú
s odznakom „soon(TM)“. Nikto na ňu nemôže kliknúť ani sa k nej dostať cez
adresu a nič na zariadení sa trhu na nič nepýta. Prepínač zdieľania disku
(losos.sharingMyStorage) je na tomto paneli, takže zdieľanie disku s mesh sa
otvorí spolu s trhom a UI ho dovtedy nedokáže zapnúť. Zvyšok tejto stránky
opisuje, ako bude trh fungovať, keď sa otvorí. Aj potom je predvolene
vypnutý, a to na troch úrovniach.
| Predvolene | Prepínač | |
|---|---|---|
| Edge ho poskytuje | vypnuté | losos.edge.market.enable |
| Zariadenie môže obchodovať | vypnuté | losos.edge.tenants.<id>.market |
| Predajca môže ponúkať | zatvorené | Stripe hlási pripojený účet ako pripravený |
Zariadenie, ktoré nikdy neobchoduje, to neovplyvní. Trh je funkcia
losos-registrar na edge.
Trh predáva to, čo už zdieľate, a nič iné. Platí zariadeniu za úložisko
a výpočtový výkon, ktorými prispieva do mesh. Nie je to samostatný produkt.
Zariadenie môže ponúkať úložisko, len kým je jeho uzol zaradený do mesh, a výpočtový
výkon, len kým zároveň zdieľa výpočtový výkon (losos.cluster.shareCompute).
Prestaňte zdieľať a vaše ponuky okamžite zmiznú z pultu. Vrátia sa, keď
zdieľanie obnovíte, a už zaplatené objednávky to neovplyvní.
Ako sa pohybujú peniaze
Edge je Stripe platforma. Peniaze sa nikdy nedotknú zariadenia LosOS.
- Predajca sa zaregistruje (onboarding). Edge mu vytvorí pripojený účet
Stripe Express, označí ho UUID zariadenia (metadáta
losos_box_uuid) a vráti odkaz na onboarding hostovaný Stripe. Zariadenie zaregistrované ešte predtým, než označovanie existovalo, sa označí, keď jeho vlastník nabudúce otvorí stránku. - Stripe oznámi edge (
account.updated), keď účet môže prijímať prevody. Až potom môže predajca niečo ponúknuť. - Kupujúci si objedná jednotky z ponuky. Edge ich zarezervuje a vytvorí
Stripe Checkout Session ako destination charge. Kupujúci zaplatí
platforme,
transfer_data[destination]prepošle tržbu na účet predajcu aapplication_fee_amountzostane platforme. - Stripe oznámi edge (
checkout.session.completed), že platba prešla. Objednávka prejde do stavupaid.
Poplatok je feeBps bázických bodov z hrubej sumy, zaokrúhlený polovicou
nahor. Pri predvolenej hodnote 400 zaplatí predaj za 20.00 EUR platforme 0.80
a predajcovi 19.20. Nastavená hodnota je obmedzená na 2000 (20 %).
Čo sa predáva
| Druh | Jednotka | Význam |
|---|---|---|
storage | GiB-mesiac | Kapacita v Longhorn poole mesh |
compute | vCPU-hodina | Plánovanie na uzle predajcu, v rámci jeho okna |
vm | replika-mesiac | Replika virtuálneho stroja na zariadení predajcu, delené 50/50 |
Stroje majú vlastnú stránku, Virtuálne stroje, a vlastný panel v administrácii.
Ceny sú v menšej jednotke (centoch) jednej meny na edge
(losos.edge.market.currency). Jedna objednávka musí mať spolu aspoň 50
menších jednotiek, čo je minimum Stripe.
Plnenie
Zaplatená objednávka je 30-dňový nárok (expires_at). Výpočtové jednotky
sa po jeho vypršaní vrátia do ponuky. Jednotky úložiska sa vrátia, až keď
claim zmizne, pretože claim drží kapacitu v Longhorne aj po skončení mesiaca.
- Úložisko. Edge vytvorí v mesh klastri namespace
market-<buyer id>aPersistentVolumeClaimzakúpenej veľkosti, pomenovaný podľa objednávky (ord-...), zlosos.edge.market.storageClass(predvolenelonghorn). Beží to po každom prechode reconcile a hneď po webhooku o zaplatení. Je to idempotentné, keďže odpoveďAlreadyExistssa počíta ako hotovo, a ak apiserver odmietne, skúša sa to znova v každom intervale reconcile. Objednávka sa považuje za splnenú, až keď je claimBound. Claim, ktorý zostalPending(taká storage class neexistuje alebo chýba kapacita), sa kontroluje znova pri každom prechode. Predpokladá to triedu s väzbouImmediate, čo je predvolená trieda Longhornu. TriedaWaitForFirstConsumersa nikdy neviaže, pretože claim zatiaľ nič nepripája. Prehľad účtu hlási naviazaný claim akovolume: "<namespace>/<claim>". Edge si meno claimu zapíše skôr, než oň požiada, takže claim, ktorý sa nikdy nenaviaže, alebo taký, ktorý vznikol tesne pred zastavením edge, si po skončení mesiaca stále ponechá svoje jednotky predané. - Výpočtový výkon. Kredit vo vCPU-hodinách, uvedený pod
entitlements. Zatiaľ ho nič nemeria ani podľa neho neplánuje.
Obmedzenia, o ktorých treba vedieť a z ktorých sa zatiaľ žiadne nevynucuje:
- Claim nie je pripnutý k uzlu predajcu. Longhorn rozmiestňuje repliky po celom poole, takže predajca dostáva zaplatené za príspevok doň, nie za hosťovanie práve tohto zväzku.
- Kupujúci nemá ku claimu žiadnu prístupovú cestu; existuje v klastri, aby ho mohol pripojiť nejaký workload.
- Nič sa nikdy nemaže. Vypršaný nárok sa prestane hlásiť, ale zväzok drží
dáta kupujúceho a jeho odstránenie je na rozhodnutí operátora. Kým operátor
claim nezmaže, jeho GiB zostávajú predané, takže tá istá kapacita sa nikdy
nepredá dvakrát. Platí to aj pre claim, ktorý je stále
Pending, keďže sa ešte môže naviazať. Prechod reconcile kontroluje každý vypršaný claim a jeho jednotky vráti do predaja, keď naň apiserver odpovie 404. - ServiceAccount registrara získa po zapnutí trhu
get/createna namespaces a PersistentVolumeClaims v celom klastri. Kubernetes RBAC nedokáže ani jedno obmedziť na menámarket-*.
Admin UI
Dnes je riadok Nastavenia, Trh sivý a označený „soon(TM)“. Je to
vypnuté tlačidlo, ktoré klávesnica preskakuje, a /settings/market namiesto
neho otvorí predvolený panel. Na otvorenie stačí jeden príznak, planned na
riadku v admin-ui/app/src/screens/settings/panes.ts, plus zodpovedajúci
prepínač v admin-ui/app/tests/app.browser.mjs, ktorý dovtedy drží
prehliadačové kontroly panela.
Po otvorení panel začína prepínačom zdieľania disku. Presunul sa sem z panela Úložisko, pretože požičiavanie disku iným zariadeniam a platba zaň sú jedno rozhodnutie. Pod ním je to, čo vlastník kúpil, s expiráciou a zväzkom, a pult, z ktorého sa nakupuje. Na predaj slúži nastavenie výplat Stripe, formulár ponuky a vlastníkove vlastné ponuky a predaje. Prepínač sa zobrazuje bez ohľadu na to, či edge tomuto zariadeniu trh ponúka, pretože je to nastavenie zariadenia, nie edge.
- Formulár ponuky ponúka len to, čo sa už zdieľa: úložisko, keď sa zariadenie pripojilo k mesh, výpočtový výkon, keď zároveň zdieľa výpočtový výkon. Všetko ostatné je sivé s uvedeným dôvodom. Edge vynucuje to isté pravidlo, panel ho len vysvetľuje.
- Platba a onboarding do Stripe otvárajú vlastné stránky Stripe na novej
karte. Nič v admin UI kartu nevidí. lososd a potom znova stránka overia,
že odkaz je stránka
https://checkout.stripe.comalebohttps://connect.stripe.com, takže skompromitovaný edge nemôže poslať vlastníka na podvrhnutý formulár na kartu. Vlastné domény Checkout nie sú podporované. - Stránky nemôžu volať edge samy, keďže CSP admin UI je
connect-src 'self'. Namiesto toho to preposielalososd:GET /api/marketaPOST /api/market/{onboard,listings,listings/close,orders}. Relay používa URL registrara, id appliance a proxy token, ktoré už poskytujelosos.proxy.enable. Vyžaduje https a token posiela docurlcez stdin, nie na príkazovom riadku. - Tam, kde je trh vypnutý (žiadna proxy, edge ho má vypnutý alebo tento
tenant nie je prihlásený),
GET /api/marketodpovie{"available": false}so stavom 200 a panel to tak aj povie. Zámerne to nie je 404. Admin UI berie 404 ako „toto zariadenie túto routu neposkytuje“ po zvyšok relácie.
API
Všetky routy sú na verejnom API registrara (register.<publicDomain>).
Overené routy berú rovnaké appliance_id a token ako /register.
Telá sú JSON.
| Routa | Overenie | Účel |
|---|---|---|
GET /market/listings | žiadne | Čo sa dá teraz kúpiť. Nemenuje žiadneho predajcu |
POST /market/account | token | Vaše ponuky, nákupy, predaje, nároky |
POST /market/seller/onboard | token | Spustiť alebo obnoviť onboarding do Stripe |
POST /market/listings | token | kind, unit_price, capacity |
POST /market/listings/close | token | listing_id; zaplatené objednávky si jednotky ponechajú |
POST /market/orders | token | listing_id, quantity; vráti URL Checkout |
POST /market/webhook | podpis | Udalosti Stripe |
Každá routa odpovedá 503, keď je trh vypnutý. Na tokenových routách dostane
tenant bez bitu market odpoveď 403. Verejný prehľad ponúk a webhook
nepatria žiadnemu tenantovi, takže to sa im nikdy nestane. POST /market/account
vracia 100 najnovších nákupov a predajov na každej strane, živé ako prvé.
Zatvorená ponuka, z ktorej si nikto neobjednal, sa zmaže; ponuka
s objednávkami zostáva, kým zostávajú ony. Ani jedna strana sa nedozvie id
appliance tej druhej a verejný prehľad ponúk ho nikdy neukazuje.
Edge rezervuje kapacitu pri vytvorení Checkout Session a drží ju, kým Stripe
neoznámi, ako sa session skončila: zaplatená (checkout.session.completed)
alebo opustená (checkout.session.expired, posielaná, keď uplynie 31 minút
session). Udalosť expired sa počíta, len ak menuje session, ktorú si
objednávka zaznamenala. Ak sa Stripe nedá zastihnúť, aby session vytvoril,
edge kapacitu okamžite uvoľní, pokiaľ zaň už nedorazila platba. Ak nedorazí
ani jedna udalosť, rezervácia vyprší po trojdňovom okne opakovaní Stripe,
takže platba oneskorená výpadkom edge stále nájde svoje jednotky nepredané.
Nasledujúci prechod reconcile potom zaznamená objednávku ako expired.
Platba, ktorá príde ešte neskôr, sa uzná, ak sú jednotky stále voľné. Inak ju
edge zaloguje s jej session id, aby ju operátor mohol vrátiť. Dvaja kupujúci,
ktorí súperia o posledné jednotky, nemôžu session dostať obaja.
Nastavenie pre operátora
-
V Stripe dashboarde zapnite Connect na účte platformy.
-
Zapečaťte tajný kľúč (stačí aj obmedzený kľúč) pomocou
systemd-creds, pričom ho čítajte zo stdin, aby sa otvorený text nikdy nedotkol disku:systemd-creds encrypt --name=stripe-secret-key - \/var/secrets/losos-stripe-secret-key.credCesta k blobu je
losos.edge.market.stripeSecretKeySealeda dešifruje ho vždy len jednotka gate. Meno musí byť presnestripe-secret-key, pretože blob sa dešifruje len pod menom, s ktorým bol zapečatený. -
Pridajte dva webhook endpointy, oba na
https://register.<publicDomain>/market/webhook: jeden pre udalosti na vašom účte (checkout.session.completed,checkout.session.expired) a jeden, ktorý počúva events on Connected accounts (udalosti na pripojených účtoch,account.updated). Stripe každý podpisuje vlastným tajomstvom, takže zapečaťte obe tajomstváwhsec_..., každé na samostatnom riadku, pod menomstripe-webhook-secretdolosos.edge.market.webhookSecretSealed(predvolene/var/secrets/losos-stripe-webhook-secret.cred). Edge prijme ktorékoľvek. -
Nastavte
losos.edge.market.enable = truealosos.edge.market.returnUrl, absolútnu http(s) URL bez prihlasovacích údajov a bez#fragment(objednávka a stav sa pripoja ako parametre dopytu). -
Nastavte
losos.edge.tenants.<id>.market = truepre každé zariadenie, ktoré smie obchodovať.
Začnite v Stripe test mode (testovací režim). Edge bol testovaný len proti náhrade za Stripe. Tá overí, čo edge posiela a ako reaguje, no nevie povedať, či to Stripe prijme. To rozhodne prvý beh v testovacom režime.
Testovací a ostrý režim
Edge prečíta režim z kľúča. Kľúče sk_test_ a rk_test_ spustia trh v
testovacom režime, sk_live_ a rk_live_ v ostrom, a žiadne zvláštne
nastavenie, ktoré by s kľúčom nesúhlasilo, neexistuje. Gate zapíše režim do
logu pri štarte a odmietne štartovať s kľúčom, z ktorého režim nevie
prečítať. Každá odpoveď trhu (/market/listings, /market/account,
onboarding a checkout) nesie "mode": "test" alebo "mode": "live".
Každý režim má vlastnú knihu: market.json pre ostrý a market-test.json
vedľa neho pre testovací. Prechod do ostrého režimu je zapečatenie ostrého
kľúča a reštart gate. Testoví predajcovia, ponuky a objednávky zostanú v
testovacej knihe, ostrý pult začína prázdny a každý predajca prejde
onboardingom znova s ostrým účtom Stripe. Testovací kľúč vráti testovaciu
knihu, ako bola. market.json zapísaný predtým, ako edge režimy oddeľoval, edge
číta ako ostrú knihu. Zväzky, ktoré si vzali testovacie objednávky, zostanú v
sieti, kým ich operátor neodstráni.
Webhook secrets režim nenesú, každá udalosť Stripe áno (livemode).
Podpísaná udalosť z druhého režimu znamená, že zapečatený webhook secret a
kľúč sú z rôznych režimov, preto ju gate odmietne a do logu zapíše, ktorý je
ktorý. Stripe odmietnutú udalosť skúša znova tri dni, takže kým sa v tom čase
zapečatí zodpovedajúci pár, nič sa nestratí.
Bezpečnostné vlastnosti
- Webhook je overený HMAC podpisom Stripe nad surovým telom, s päťminútovým oknom proti opakovaniu a vyšším limitom tela než ostatné routy.
- Platba sa počíta, len keď sa session id, suma a mena zhodujú s tým, čo edge zaznamenal pre objednávku. Nezhoda sa zaloguje a nesplní sa. Ak sa edge zastavil skôr, než si session id zapísal, prevezme sa id z podpísanej udalosti, keďže objednávku v nej mohol pomenovať len gate tohto edge.
- Registrar nikdy nedrží kľúč Stripe. Samostatná jednotka,
losos-stripe-gate(losos-registrar stripe-gate), je jediný proces, ktorý ho má. Registrar s gate komunikuje cez Unix socket (/run/losos-stripe-gate/gate.sock, 0600) a smie žiadať len o vytvorenie účtu, označenie účtu, kontrolu účtu, vytvorenie odkazu na onboarding, spustenie Checkout Session alebo overenie podpisu webhooku. Gate odmietne checkout, ktorého cieľ nie je idacct_..., ktorého mena sa líši od nastavenej, ktorého poplatok presahuje strop 20 % alebo celú sumu, ktorého návratová URL nie je obyčajná http(s) URL alebo ktorého session žije dlhšie ako deň. Odmietne aj Stripe endpoint, ktorý nie jehttps. Neexistuje operácia „prepošli toto do Stripe“. Skompromitovaný registrar preto nemôže prečítať kľúč, nemôže poslať peniaze nikam inam než na pripojený účet v rámci limitov poplatkov gate a nemôže vystavovať refundácie ani výplaty. Stále môže žiadať o checkouty, pretože to je jeho úloha. Obe jednotky bežia ako procesy na tom istom stroji a root na edge sa stále dostane k obom. Ako druhá vrstva jednotka registrara označí zapečatené bloby a adresár s credentials gate ako nedostupné. - Edge nikdy neukladá tajomstvá Stripe v otvorenom texte. Sú uložené ako
bloby
systemd-creds, zapečatené pomocou TPM2, kde ho edge má, a inak kľúčom hostiteľa, a ku gate sa dostanú cezLoadCredentialEncrypted=. V otvorenom texte sú len v súkromnom credential tmpfs tejto jednotky a kópia/varnesie len šifrovaný text. Rotácia tajomstva znamená zapečatiť nový blob a reštartovaťlosos-stripe-gate. Chýbajúci blob gate preskočí, čo vypne trh (503) a nič iné. Gate je samostatná jednotka, takže master proxy v registrari si to ani nevšimne. - Účet Stripe nesie UUID zariadenia, nie jeho kód na obnovenie. Kód na
obnovenie je prihlasovací údaj a zostáva na zariadení. Zariadenie posiela jednosmernú
hodnotu z neho odvodenú, prvých 16 bajtov
SHA-256("losos-box-id-v1:" + code)naformátovaných ako UUID. Je stabilná po celú životnosť inštalácie a neprezrádza nič, z čoho by sa dal kód obnoviť. Registrar overí, že ide o kanonické UUID. Prehliadač ho nemôže zvoliť, pretože ho pridáva sám lososd. - Súbory s tajomstvami sa pred použitím kontrolujú na tvar (
sk_/rk_,whsec_). market.jsonmá 0600 a zapisuje sa atomicky. Súbor, ktorý sa nedá sparsovať, zabráni spusteniu edge. Považovať ho za prázdny by znamenalo zabudnúť, kto za čo zaplatil.- Chybové texty a endpointy Stripe zostávajú v žurnále; volajúci dostanú pevnú správu.
Čo nie je pokryté
- Refundácie a spory. Riešte ich v Stripe dashboarde pomocou
reverse_transferarefund_application_fee, aby sa vrátil podiel predajcu aj provízia platformy. Trh nemodeluje ani jedno. - Vynucovanie nároku. Plnenie vytvorí claim; nebráni kupujúcemu použiť viac, než kúpil, nemeria výpočtový výkon a pri expirácii neodoberá prístup.
- Dane, fakturácia a overovanie predajcov nad rámec toho, čo robí onboarding Stripe. Prevádzka trhoviska prináša právne povinnosti, ktoré závisia od toho, kde pôsobíte. Toto je experiment, nie rada.