mirror of
https://github.com/photoprism/photoprism.git
synced 2026-01-23 02:24:24 +00:00
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
parent
90f62a732e
commit
52337eba27
6 changed files with 21 additions and 11 deletions
|
|
@ -349,7 +349,7 @@ If anything in this file conflicts with the `Makefile` or the Developer Guide, t
|
|||
|
||||
### Cluster Operations
|
||||
|
||||
- Keep bootstrap code decoupled: avoid importing `internal/service/cluster/instance/*` from `internal/config` or the cluster root, let instances talk to the Portal over HTTP(S), and rely on constants from `internal/service/cluster/const.go`.
|
||||
- Keep bootstrap code decoupled: avoid importing `internal/service/cluster/node/*` from `internal/config` or the cluster root, let nodes talk to the Portal over HTTP(S), and rely on constants from `internal/service/cluster/const.go`.
|
||||
- Config init order: load `options.yml` (`c.initSettings()`), run `EarlyExt().InitEarly(c)`, connect/register the DB, then invoke `Ext().Init(c)`.
|
||||
- Theme endpoint: `GET /api/v1/cluster/theme` streams a zip from `conf.ThemePath()`; only reinstall when `app.js` is missing and always use the header helpers in `pkg/service/http/header`.
|
||||
- Registration flow: send `rotate=true` only for MySQL/MariaDB nodes without credentials, treat 401/403/404 as terminal, include `clientId` + `clientSecret` when renaming an existing node, and persist only newly generated secrets or DB settings.
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ Background Workers
|
|||
|
||||
Cluster / Portal
|
||||
- Node types: `internal/service/cluster/const.go` (`cluster.RoleInstance`, `cluster.RolePortal`, `cluster.RoleService`).
|
||||
- Instance bootstrap & registration: `internal/service/cluster/instance/*` (HTTP to Portal; do not import Portal internals).
|
||||
- Node bootstrap & registration: `internal/service/cluster/node/*` (HTTP to Portal; do not import Portal internals).
|
||||
- Registry/provisioner: `internal/service/cluster/registry/*`, `internal/service/cluster/provisioner/*`.
|
||||
- Theme endpoint (server): GET `/api/v1/cluster/theme`; client/CLI installs theme only if missing or no `app.js`.
|
||||
- See specs cheat sheet: `specs/portal/README.md`.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package instance
|
||||
package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -31,18 +31,19 @@ var log = event.Log
|
|||
|
||||
func init() {
|
||||
// Register early so this can adjust DB settings before connectDb().
|
||||
config.RegisterEarly("cluster-instance", InitConfig, nil)
|
||||
config.RegisterEarly("cluster-node", InitConfig, nil)
|
||||
}
|
||||
|
||||
// InitConfig performs instance bootstrap: optional registration with the Portal
|
||||
// InitConfig performs node bootstrap: optional registration with the Portal
|
||||
// and theme installation. Runs early during config.Init().
|
||||
func InitConfig(c *config.Config) error {
|
||||
if !cluster.BootstrapAutoJoinEnabled && !cluster.BootstrapAutoThemeEnabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
role := c.NodeRole()
|
||||
// Skip on portal nodes and unknown node types.
|
||||
if c.IsPortal() || c.NodeRole() != cluster.RoleInstance {
|
||||
if c.IsPortal() || (role != cluster.RoleInstance && role != cluster.RoleService) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +123,7 @@ func registerWithPortal(c *config.Config, portal *url.URL, token string) error {
|
|||
payload := cluster.RegisterRequest{
|
||||
NodeName: c.NodeName(),
|
||||
NodeUUID: c.NodeUUID(),
|
||||
NodeRole: cluster.RoleInstance,
|
||||
NodeRole: c.NodeRole(),
|
||||
AdvertiseUrl: c.AdvertiseUrl(),
|
||||
}
|
||||
// Include client credentials when present so the Portal can verify re-registration
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package instance
|
||||
package node
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
|
|
@ -27,6 +27,15 @@ func TestInitConfig_NoPortal_NoOp(t *testing.T) {
|
|||
assert.NoError(t, InitConfig(c))
|
||||
}
|
||||
|
||||
func TestInitConfig_ServiceRole(t *testing.T) {
|
||||
c := config.NewMinimalTestConfigWithDb("bootstrap-service", t.TempDir())
|
||||
defer c.CloseDb()
|
||||
|
||||
c.Options().NodeRole = cluster.RoleService
|
||||
|
||||
assert.NoError(t, InitConfig(c))
|
||||
}
|
||||
|
||||
func TestRegister_PersistSecretAndDB(t *testing.T) {
|
||||
// Fake Portal server.
|
||||
var jwksURL string
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Package instance bootstraps a PhotoPrism node that joins a cluster Portal.
|
||||
Package node bootstraps a PhotoPrism node (instance or service) that joins a cluster Portal.
|
||||
|
||||
Responsibilities include:
|
||||
|
||||
|
|
@ -35,4 +35,4 @@ want to support our work, or just want to say hello.
|
|||
Additional information can be found in our Developer Guide:
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
*/
|
||||
package instance
|
||||
package node
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package instance
|
||||
package node
|
||||
|
||||
import (
|
||||
"os"
|
||||
Loading…
Add table
Add a link
Reference in a new issue