package cli import ( "context" "errors" "fmt" "net" "os" "path/filepath" "time" "gitea.mynodes.xyz/ilker/llmgw/internal/bundle" "gitea.mynodes.xyz/ilker/llmgw/internal/config" "gitea.mynodes.xyz/ilker/llmgw/internal/mirror" "gitea.mynodes.xyz/ilker/llmgw/internal/settings" "gitea.mynodes.xyz/ilker/llmgw/internal/tlsconf" ) // --- installing from an offline bundle --- // checkBundle refuses, before anything is done, a bundle init could not // install from: one that is not there, or not the one that was made. func (in *serverInit) checkBundle() error { if in.bundle == "" { return nil } if in.noMirror && in.mirrorURL == "" { return errors.New("a bundle goes into the cluster's mirror: leave out --no-mirror, or give --mirror") } if in.bundleSHA == "" { return errors.New("give --bundle-sha256, the sha256 'llmgw bundle create' printed: " + "it is what says the bundle that arrived is the one that was made") } _, digest, err := bundle.ReadManifest(in.bundle) if err != nil { return err } if digest != in.bundleSHA { return fmt.Errorf("the bundle's sha256 is %s, not the %s given: it is not the bundle that was made, "+ "or the digest was mistyped", digest, in.bundleSHA) } return nil } // bundleCarries says whether the bundle holds a model of this name. func (in *serverInit) bundleCarries(model string) bool { m, _, err := bundle.ReadManifest(in.bundle) if err != nil { return false } for _, md := range m.Models { if md.Name == model { return true } } return false } // offline says whether this cluster is set up to reach nothing outside. func (in *serverInit) offline() bool { if in.bundle != "" { return true } cfg, err := loadEffectiveConfig(in.configPath()) return err == nil && cfg.Offline.Enabled() } func (in *serverInit) mirrorRoot() string { if in.mirrorPath != "" { return in.mirrorPath } return mirrorDir } // ensureBundle puts the bundle into the mirror beside this control plane, // has the control plane trust its engines' checksums, and says in // server.yaml that the cluster is offline. With a mirror on another // machine, the files are imported there; here only the checksums are kept. func (in *serverInit) ensureBundle(ctx context.Context) error { cfg, err := loadEffectiveConfig(in.configPath()) if err != nil { return err } var ( m bundle.Manifest files string ) if in.mirrorURL == "" { res, err := bundle.Import(in.bundle, bundle.ImportOptions{Mirror: in.mirrorRoot(), SHA256: in.bundleSHA}) if err != nil { return err } if res.Written > 0 { in.done("offline bundle in the mirror: %d files, %s, each checked", res.Written, fileSize(res.Bytes)) } else { in.kept("offline bundle in the mirror (%d files)", res.Kept) } m = res.Manifest files = "http://" + net.JoinHostPort(in.reachableAddr(), "8081") } else { mc, err := mirror.NewClient(in.mirrorURL, tlsconf.Config{}, 10*time.Second) if err != nil { return err } list, err := mc.List(ctx) if err != nil { return fmt.Errorf("asking the mirror at %s where nodes reach it: %w", in.mirrorURL, err) } files = list.Base if m, _, err = bundle.ReadManifest(in.bundle); err != nil { return err } fmt.Fprintf(in.out, " !! the mirror is on another machine: import the bundle there too, "+ "sudo llmgw bundle import --sha256 %s\n", in.bundleSHA) } sums := cfg.Offline.Checksums if sums == "" { sums = filepath.Join(in.etcDir, "offline.sha256") } n, err := bundle.TrustManifest(m, sums) if err != nil { return err } in.done("the control plane trusts %d engine files from the bundle (%s)", n, sums) if cfg.Offline.Enabled() { in.kept("offline, installing from %s, as server.yaml says", cfg.Offline.Mirror) return nil } if sums == config.DefaultOfflineChecksums { sums = "" } // In the cluster's settings once the store holds them; in server.yaml // before, where the first start brings it in. stored, err := changeStoredSettings(in.configPath(), "offline, from server init --bundle", func(doc *settings.Doc) error { if err := doc.SetYAML([]string{"offline", "mirror"}, files); err != nil { return err } if sums != "" { return doc.SetYAML([]string{"offline", "checksums"}, sums) } return nil }) if err != nil { return err } if stored { in.done("the cluster's settings: offline, nodes install from the mirror at %s", files) return nil } if err := appendOfflineBlock(in.configPath(), files, sums); err != nil { return err } in.done("server.yaml: offline, nodes install from the mirror at %s", files) return nil } // appendOfflineBlock says in server.yaml that the cluster is offline, // without touching the rest. func appendOfflineBlock(path, files, sums string) error { b, err := os.ReadFile(path) //nolint:gosec // server.yaml if err != nil { return err } info, err := os.Stat(path) if err != nil { return err } block := "\n# Offline: nothing in the cluster reaches the internet. Nodes install\n" + "# engines, and upgrades fetch releases, from the mirror, out of the bundle\n" + "# 'llmgw server init --bundle' imported; 'llmgw bundle import' adds more.\n" + "offline:\n mirror: " + files + "\n" if sums != "" { block += " checksums: " + sums + "\n" } return os.WriteFile(path, append(b, []byte(block)...), info.Mode().Perm()) }