Blueforce-Linux/docs/27-OFFLINE-PROVISIONING.md
emirhanmamak-blueforce 06c96690ca fix(offline): keep the package payload out of a clone, and say so when it is missing
The bundle pool is ~884 MB and now travels through Git LFS, so a plain clone
materialises all of it. Measured on this repository: 2.7 GB working tree, against
20 MB with smudge disabled -- the same 135x that decides whether one device or
seven hundred can be provisioned from a git remote.

bf-bootstrap exports GIT_LFS_SKIP_SMUDGE=1 for every git operation it performs
(clone and fetch), so provisioning a device no longer implies downloading the
package payload. The trade is explicit and documented rather than hidden: with
smudge off the pool files on disk are 131-byte pointer texts, and the installer
must not mistake one for a package.

So the installer gained a guard. A pointer text satisfies every existence check,
so without it the run died later inside `sha256sum -c` and reported a checksum
mismatch -- a misdiagnosis that sends an operator looking for corruption when the
payload was simply never fetched. It now recognises the pointer by content and
names the remedy instead.

Getting the payload is a deliberate second step, and both documented routes are
real: a local mirror (the offline-correct path, and the one the fleet uses) or
`git lfs pull --include='provisioning/offline-repo/built/pool/*'`, which fetches
only the delivery pool and leaves the intake copy under packages/ unfetched --
verified: 1.8 GB and a real .deb in built/pool, 131-byte stub still in packages/.

Tests: test-field-os-lifecycle.sh gains a scenario that lays down a pointer text
where a .deb belongs and asserts three things -- the run refuses, the message
names the cause, and it does not blame a checksum. Also asserts apt-get is never
invoked. 16 scenarios, all passing.

docs/27 is corrected where it had gone stale: it claimed a clone carries the
packages and the installer downloads nothing, which stopped being true the moment
the payload moved to LFS.
2026-09-16 22:41:53 +03:00

18 KiB
Raw Blame History

27 — Offline Provisioning

Kısa özet: Paketler git deposunun içindedir (provisioning/offline-repo/built/pool/, 1321 .deb, ~884 MB, Git LFS ile takip edilir). Saha kurulumu internet gerektirmez: sudo bf → Kurulum sekmesi → "Bu cihazı kur" → 8 haneli bayi no → onay. Paket yükü klonla birlikte gelmez (bilerek; bkz. §4), yerel aynadan taşınır ve kurucu depoyu kendi bulur. Bu yol yalnız PROVISIONED_OFFLINE durumuna getirir; cihaz, tek kullanımlık enrollment token ve merkezi kanallar doğrulanmadan ENROLLED veya READY olmaz.

  • Dosya: docs/27-OFFLINE-PROVISIONING.md

Uygulama sözleşmesi: Kurucu, paket setini kendi kendine bulur ve varsayılan olarak yerel depodan kurar; --offline bayrağı artık gerekmez (geriye uyumluluk için kabul edilir, yalnız yerel depoyu zorlar). Arama sırası: (1) BF_OFFLINE_REPO ortam değişkeni, (2) <depo>/provisioning/offline-repo/built, (3) /opt/blueforce/offline-repo; ilk eksiksiz aday kazanır. Yerel file: APT kaynağı dışında hiçbir kaynak kullanılmaz: uzak APT source, curl, wget, anahtar indirme veya apt download çağrılmaz. İnternet kurulum için gerekmez. İki farklı başarısızlık vardır: depo hiç yoksa kurulum Türkçe bir hata, aranan yollar ve ÇIKIŞ NEDENİ: yerel paket deposu bulunamadı. ile durur; depo bulunup da doğrulanamazsa (eksik Packages, Packages.gz, packages.lock.tsv, SHA256SUMS; checksum uyuşmazlığı; boş/bozuk kilit; eksik pin) OFFLINE BLOCKED: <sebep> ile durur. Her iki durumda da paket modüllerinden önce durulur, kurulum başlamaz ve sistemde hiçbir değişiklik yapılmaz. Paketler bu git deposunda taşınır ve repo sorumlusu tarafından add-packages.sh + build-index.sh ile bu depoya konur; kuran kişi hiçbir şey indirmez. Yalnız geliştirme/test için --online vardır ve üretim cihazlarında kullanılmaz. Grafik arayüz python3-tk paketine bağlıdır; bu paket offline depoda bilinçli olarak pinlidir (manifests/base-packages.txt).

  • İlgili kararlar: 24-DECISION-LOG.md#K-16, #K-09, #K-11, #K-12
  • İlgili dokümanlar: 05-ONE-CLICK-INSTALLER.md (kurucu), 33-OPERATOR-CONSOLE.md (arayüz), provisioning/offline-repo/README.md (paket hazırlama)
  • Durum: [ ] Taslak

1. Amaç

Saha interneti kesik veya güvenilmezken tekrarlanabilir, denetlenebilir ve secretsiz ilk kurulumu tanımlamak. Kuran kişi paket aramaz, indirmez, bayrak ezberlemez: paket seti depoda sürümlenir ve yerel aynadan taşınır.

2. Kapsam

  • Kapsam içi: git checkout (paketler dahil) veya kurulmuş /opt/blueforce/offline-repo, offline APT bundle (built/), kurucunun yerel depoyu otomatik bulması, iki hata durumu, grafik arayüz üzerinden kurulum, python3-tk pini, durum damgası ve sonradan enrollment.
  • Kapsam dışı: merkezi peer atama ve token doğrulama (29), release imzalama (30), paket setinin nasıl üretildiği (repo sorumlusunun işi, provisioning/offline-repo/README.md).

3. Kararlar

KARAR:    Paket seti git deposunda taşınır ve cihaz grafik arayüzden (`sudo bf` → Kurulum → "Bu cihazı kur") internetsiz kurulur; paket deposu kurucu tarafından otomatik bulunur ve sonuç durumu yalnızca PROVISIONED_OFFLINE'dır.
GEREKÇE:  Paket indirme veya merkezi API'ye erişim yokken cihaz standarda getirilebilir; fakat merkezde doğrulanmamış kimlik ve kanallar READY iddiası yapamaz. Kuran kişinin indirme yapmaması ve bayrak hatırlamaması saha hatasını ortadan kaldırır: yerel depo varsayılan ve tek kaynaktır.
ALTERNATİF: İnternet gelene kadar kurulum yapmama — saha ziyareti ve bekleme maliyeti nedeniyle elendi. Kurulumu `--offline` bayrağına bağlamak — operatör bayrağı unuttuğunda kurulum durur; otomatik keşif seçildi, bayrak geriye uyumluluk için korundu.
RİSK:     Eski veya karışık paket snapshot'ı; manifest, checksum ve release kimliği ile azaltılır. Yanlış/eski depo bulunması; arama sırası ve her adayda eksiksizlik denetimi ile azaltılır. Grafik arayüzün `python3-tk` paketine bağımlılığı; paketin offline depoda pinlenmesi ve eksikliğinde `sudo bf --tui` yedeği ile azaltılır.
MALİYET:  Ücretsiz (depo boyutu git tarafında ~888 MB).
LİSANS:   APT — https://manpages.ubuntu.com/manpages/noble/en/man8/apt.8.html ; dpkg — https://manpages.ubuntu.com/manpages/noble/en/man1/dpkg.1.html ; Ubuntu offline kurulum ayrıntısı 26.04 için LAB doğrulamalıdır.

4. Neden Bu Karar?

Paketler ayrı bir medyada değil, bu git deposunda taşınır: provisioning/offline-repo/built/pool/ altında 1321 .deb (~884 MB) durur ve .gitattributes ile Git LFS üzerinden takip edilir (*.deb filter=lfs ...). Bu yüzden sahada "hangi paket nereden geldi?" sorusu ne internete ne de dış medyaya bağlıdır; aynı soru packages.lock.tsv ve repo-manifest.yaml ile yanıtlanır.

Kuran kişi paket aramaz, ama paket yükünü kendiliğinden de indirmez — bu bilinçli bir ayrımdır. LFS yükü ~884 MB olduğu ve 700 cihazın her biri onu çekerse aylık bant kotası ilk günde tükeneceği için klon hafif tutulur; yük yerel aynadan (USB ya da repo sorumlusunun bıraktığı kopya) gelir, sahada internet gerekmez. Yalnız internet varken ve tek seferlik bir çekme uygunsa git lfs pull --include='provisioning/offline-repo/built/pool/*' kullanılır.

Durum makinesi, "kuruldu" ile "merkezce güvenildi" arasındaki farkı görünür yapar: offline kurulum yalnız PROVISIONED_OFFLINE üretir.

5. Alternatifler

Alternatif Artı Eksi Sonuç
Sürümlü offline APT bundle + repoda taşınan paketler Tekrarlanabilir, indirme yok, medya lojistiği yok Git deposu ~888 MB büyür (LFS) Seçildi
Ayrı fiziksel seed USB medyası Depo küçük kalır Medya zimmeti/sürüm takibi, kaybolma riski Yedek/geri dönüş yolu
Rastgele .deb dosyaları İlk anda kolay Bağımlılık/sürüm belirsiz Elendi
İnternet bekleme Basit Saha blokajı Elendi
Yerel depoyu operatörün --offline bayrağıyla göstermesi Basit Bayrak unutulunca kurulum durur, saha hatası üretir Elendi (bayrak geriye uyumluluk için korundu)

6. Avantajlar

  • Bağlantısız sahada standarda yakın kurulum; kuran kişi hiçbir indirme yapmaz ve bayrak ezberlemez.
  • Paket manifesti ve kilit dosyası ile hangi sürümün yüklendiği kanıtlanır.
  • Nesil farkı yoktur: repo sorumlusu paketleri bir kez commit eder, 700 cihaz aynı setten kurulur.
  • Kurulum akışı grafik arayüzde tek düğmedir; terminal bilgisi gerekmez.

7. Dezavantajlar

  • Git deposu paket setiyle birlikte büyür (LFS; içerik-hash ile tekilleşir, ~884 MB). Klon hafiftir ama paket yükü ayrıca taşınmalıdır: 700 cihazın her biri LFS'ten çekerse bant kotası tükenir, bu yüzden yük yerel aynadan dağıtılır.
  • Offline cihaz merkezi izleme ve erişim kanalları doğrulanana kadar operasyonel olarak hazır değildir.
  • Paket snapshot'ı yenilenmediği sürece güvenlik güncellemeleri geride kalır (onaysız update zaten yasak, K-11).

8. Riskler

Risk Olasılık Etki Azaltma
Eski güvenlik paketi Orta Orta Süre sonu olan release medyası/repo sürümü, hızlı enrollment kuyruğu
Secret repoda kalır Düşük Yüksek Secret taraması (test), token yalnız bir kez ve cihazda girilir
Yarım paket işlemi Orta Orta dpkg --configure -a, idempotent kurucu
Kurucu yanlış/eski depoyu bulur Düşük Orta Arama sırası sabittir; aday eksiksiz değilse kullanılmaz, BF_OFFLINE_REPO ile açıkça yönlendirilebilir
Paketler var ama indeks (built/) yok Orta Yüksek Kurucu fail-closed durur ("yerel paket deposu yok"); repo sorumlusu build-index.sh koşup built/ dizinini commit eder
Grafik arayüz açılamıyor Orta Düşük python3-tk offline depoda pinli; ekransız ortamda sudo bf --tui

9. Uygulama Planı

  1. Medya/repo manifesti: Field OS release, ISO checksum, offline APT snapshot kimliği, kurucu commit'i.
  2. Paket setini repo sorumlusu hazırlar: .deb dosyalarını add-packages.sh ile provisioning/offline-repo/packages/ altına koyar (Git LFS), pinleri manifests/*.txt içinde package=version olarak doldurur, build-index.sh ile provisioning/offline-repo/built/ indeksini (Packages, Packages.gz, packages.lock.tsv, SHA256SUMS, pool/) üretir. Kuran kişi yalnız git tarafını çeker.
  3. Kurulumda yalnız genel paketler kullanılır; kurucu yerel depoyu otomatik bulur ve --offline gerekmez.
  4. Kurucu yerel durum dosyasına PROVISIONED_OFFLINE yazar; READY yazması yasaktır.
  5. İnternet geldiğinde 29'daki tek-kullanımlık token ile enrollment başlatılır; sonra merkezi kanallar test edilir.

Kuran kişinin akışı (grafik arayüz — ana yol)

  1. Depoyu getir: git clone <repo> — paketler bilerek gelmez. Bootstrap (ve her git işlemi) GIT_LFS_SKIP_SMUDGE=1 ile çalışır, çünkü paket yükü ~884 MB'tır ve tam klon sahada 2.7 GB'lık bir çalışma kopyası üretir (ölçüldü; smudge kapalıyken 20 MB). Paket yükünü almanın iki yolu var:
    • Yerel ayna (önerilen, sahada internet yok): repo sorumlusunun hazırladığı /opt/blueforce/offline-repo kopyasını taşıyın; ya da

    • Hedefli LFS çekme (yalnız internet varken): depo kökünde

      git lfs pull --include='provisioning/offline-repo/built/pool/*'
      

      Bu yalnız teslim havuzunu indirir (packages/ altındaki kaynak kopyayı çekmez, aynı baytları ikinci kez indirmez). Paketler gelmediyse kurucu bunu tek cümleyle söyler (Paketler henüz indirilmemiş: … Git LFS işaretçisi), çünkü havuzdaki dosyalar .deb değil 131 baytlık işaretçi metnidir.

  2. sudo bf — pencere açılır: Blueforce Field OS — Yönetim.
  3. Üst çubuk Hedef > Bayi no (8 hane) alanına numarayı yaz (örn. 12010193).
  4. Kurulum sekmesi → Bu cihazı kur (hiçbir şey yazmayan ön kontrol için: Kurulum ön kontrolü (--check)).
  5. Komut ekranda gösterilir, onay istenir; onaylandıktan sonra kurulum çalışır. --offline işaretlemek zorunlu değildir (varsayılan kaynak zaten yerel depodur).
  6. Sonuç: PROVISIONED_OFFLINE. Arayüzdeki Kurulum modül durumu ve bf-status ile doğrulanır.
# Ana yol (grafik arayüz)
sudo bf
#   → Hedef: Bayi no (8 hane)  →  Kurulum sekmesi  →  "Bu cihazı kur"

# Yedek yol (grafik ekran yoksa veya python3-tk yoksa): aynı uygulamanın terminal arayüzü
sudo bf --tui

# Doğrudan kurucu ile (otomasyon / teşhis)
sudo ./scripts/install/blueforce-install.sh --dealer-id 12010193

# Bilinçli olarak başka bir depo dizinini göstermek (nadir, repo sorumlusu isterse)
BF_OFFLINE_REPO=/mnt/blueforce-repo/built \
  sudo ./scripts/install/blueforce-install.sh --dealer-id 12010193

Depo keşfi ve iki hata durumu

Sıra (ilk eksiksiz aday kazanır): BF_OFFLINE_REPO → <repo>/provisioning/offline-repo/built → /opt/blueforce/offline-repo. Bir aday "eksiksiz" sayılmak için Packages, Packages.gz, packages.lock.tsv ve SHA256SUMS dosyalarının hepsini içermelidir; yalnız packages/ (ham .deb havuzu) yeterli değildir — indeksin build-index.sh ile üretilmiş olması gerekir.

Depo bulunduğunda ekranda şu duyuru çıkar:

Yerel paket deposu bulundu: <N> paket, <boyut>
   Depo    : <dizin>
   Kaynak  : <bulunduğu yer>
   Kip     : yerel kurulum. İnternet, paket indirme ve ek anahtar gerekmez.

Depo hiçbir yerde yoksa kurulum başlamadan durur:

HATA: Yerel paket deposu yok. Repo sorumlusuna başvurun: provisioning/offline-repo/README.md

Aranan yerler:
  - depodaki hazır paket seti — yok: <repo>/provisioning/offline-repo/built
  - cihazdaki kurulu paket deposu — yok: /opt/blueforce/offline-repo

Ne yapmalı:
  1) Paket setini git ile tam olarak getirin ... ya da /opt/blueforce/offline-repo altına koyun.
  2) Kurulumu yeniden çalıştırın.

Kuruluma hiç başlanmadı; sistemde hiçbir değişiklik yapılmadı.
ÇIKIŞ NEDENİ: yerel paket deposu bulunamadı.

Depo bulundu ama doğrulanamadıysa (bozuk/eksik içerik) kurulum yine başlamaz:

OFFLINE BLOCKED: <sebep>
   Depo       : <dizin>
   Ne yapmalı : paket setini yeniden üretip git ile getirin (provisioning/offline-repo/README.md)
   ÇIKIŞ NEDENİ: yerel paket deposu doğrulanamadı; kurulum başlamadı ve
                 sistemde hiçbir değişiklik yapılmadı.

--online yalnız geliştirme/test makinesi içindir; paketleri internetten çeker ve üretim cihazlarında kullanılmaz.

python3-tk neden offline depoda pinli?

Grafik operatör uygulaması Tkinter ile yazılmıştır ve tkinter Ubuntu'da ayrı bir pakettir (python3-tk); minimal Ubuntu Server kurulumunda Python vardır ama tkinter yoktur. İnternetsiz sahada apt install python3-tk çalışmaz, bu yüzden paket ve bağımlılık kümesi (python3-tk, python3.14-tk, libtk8.6) provisioning/offline-repo/manifests/base-packages.txt içinde pinlidir ve depodan gelir. Kurulum sonu kapısı scripts/install/installer/modules/18-final-check.sh tkinter'ı denetler; eksikse WARN yazar ve kurulumu düşürmez (cihaz yine kurulur, operatör terminal konsoluna sudo bf --tui ile devam eder).

10. Test Planı

Test Beklenen sonuç Ortam
İnternetsiz kurulum Paketler manifestten kurulur, dış indirme yok LAB(2) air-gapped
Depo yolu verilmeden kurulum Kurucu depoyu otomatik bulur (repo/built), duyuru satırını yazar LAB(2)
Grafik arayüzden kurulum sudo bf → Kurulum → "Bu cihazı kur" ile PROVISIONED_OFFLINE LAB(2) masaüstü oturumu
BF_OFFLINE_REPO ile başka dizin Verilen dizin kullanılır; geçersizse durur LAB(2)
Depo hiç yok Türkçe hata + aranan yollar + ÇIKIŞ NEDENİ: yerel paket deposu bulunamadı., exit 1, sistem değişmez LAB(2)
Depo var ama bozuk (checksum/pin) OFFLINE BLOCKED: <sebep> + Türkçe çıkış nedeni, exit 1, sistem değişmez LAB(2)
Yalnız packages/ var, built/ yok Depo "yok" sayılır, kurulum başlamaz (fail-closed) LAB(2)
python3-tk eksik imaj sudo bf Türkçe hata + ipucu, exit 3; 18-final-check WARN yazar, kurulum düşmez LAB(2)
DNS/WAN kesik Kurucu dış indirme istemez; 01-precheck ağı yalnız bilgi olarak yazar, 05-network DNS zorunlu tutmaz LAB(2)
--online üretimde denenmez Yalnız geliştirme/test; kurucu uyarı yazar LAB(2)
bf-status PROVISIONED_OFFLINE; READY değil LAB(2)
Bağlantı sonrası enrollment ENROLLED → READY kapıları çalışır LAB(2)

11. Rollback

  1. Paket işlemi bozuksa aynı onaylı snapshot ile dpkg --configure -a ve kurucu yeniden çalıştırılır.
  2. Yanlış repo sürümü geri çekilir; önceki onaylı manifestle yeniden kurulur.
  3. Yerel depo bozuksa sahada onarılmaz: repo sorumlusu depoyu yeniden üretip commit eder (add-packages.sh + build-index.sh), kurulum yapan kişi güncel git tarafını çekip komutu tekrarlar.
  4. Kimlik/token hatasında cihaz resetlenmez; 29'daki token iptal/yenileme prosedürü uygulanır.
  5. Arayüz sorunuysa (ekran/tkinter) rollback gerekmez: sudo bf --tui ile aynı akış yürütülür.

12. Kontrol Listesi

  • Paket kaynağı repoda: provisioning/offline-repo/packages/ (1321 .deb, Git LFS ile takip ediliyor; teslim kopyası built/pool/ içindedir).
  • Bundle indeksi repoda: provisioning/offline-repo/built/ (Packages, Packages.gz, packages.lock.tsv, SHA256SUMS, pool/).
  • Paket yükü sahaya taşındı: yerel ayna (USB ya da /opt/blueforce/offline-repo) — klon LFS yükünü bilerek getirmez, bu adım atlanırsa kurucu Paketler henüz indirilmemiş: … Git LFS işaretçisi ile durur.
  • repo-manifest.yaml güncel; pin listesi ile paket havuzu uyuşuyor.
  • Depoda/repoda cihaz kimliği, private key veya kalıcı token yok.
  • python3-tk ve bağımlılıkları manifests/base-packages.txt içinde pinli; 18-final-check tkinter'ı denetliyor.
  • Kuran kişinin komutu --offline bayrağı istemiyor; depo otomatik bulunuyor.
  • Grafik arayüz akışı (bayi no → Kurulum → "Bu cihazı kur") yazılı ve ekransız ortam için sudo bf --tui belgeli.
  • İnternet kapalıyken kurulum tamamlanıyor; dış indirme çağrısı yok.
  • PROVISIONED_OFFLINE görünür ve READY kapısı kapalı.
  • Sonradan enrollment sahibi/kuyruğu kayıtlı.

13. Açık Sorular

  • Offline paket seti yenileme sıklığı ve Git LFS bant genişliği/kotaysa sahaya taşıma yöntemi — sahibi: release yöneticisi.
  • Paketlerin sahaya taşınmasında git clone mu, hazır /opt/blueforce/offline-repo kopyası mı birincil — sahibi: saha operasyonu + 05 yazarı.
  • --online geliştirme yolunun hangi ortamlarda serbest olduğu — sahibi: yönetim + 26/33 yazarları.

Ek: Keşif ve durum akışı

flowchart LR
  M["git clone (hafif: LFS smudge kapalı)<br/>+ paket yükü yerel aynadan"] --> G["sudo bf → Kurulum → 'Bu cihazı kur'"]
  G --> D{"Kurucu yerel depoyu arar<br/>BF_OFFLINE_REPO → repo/built → /opt/blueforce/offline-repo"}
  D -->|"hiçbiri yok / eksik"| X["HATA: Yerel paket deposu yok<br/>aranan yollar + ÇIKIŞ NEDENİ · exit 1<br/>sistem değişmez"]
  D -->|"eksiksiz aday bulundu"| V{"Doğrulama katmanı:<br/>dosya listesi, SHA256SUMS, kilit, pin ↔ pool"}
  V -->|"başarısız"| B["OFFLINE BLOCKED: sebep<br/>ÇIKIŞ NEDENİ: doğrulanamadı · exit 1"]
  V -->|"geçti"| P["PROVISIONED_OFFLINE"]
  P --> T["Tek kullanımlık token"]
  T --> E["ENROLLED"]
  E --> C["WG + erişim + izleme doğrulama"]
  C --> R["READY"]