diff --git a/internal/config/config_cluster.go b/internal/config/config_cluster.go index 2aecb054d..78cc3b305 100644 --- a/internal/config/config_cluster.go +++ b/internal/config/config_cluster.go @@ -13,39 +13,7 @@ import ( "github.com/photoprism/photoprism/pkg/rnd" ) -// ClusterDomain returns the cluster DOMAIN (lowercase DNS name; 1–63 chars). -func (c *Config) ClusterDomain() string { - return c.options.ClusterDomain -} - -// ClusterUUID returns a stable UUIDv4 that uniquely identifies the Portal. -// Precedence: env PHOTOPRISM_CLUSTER_UUID -> options.yml (ClusterUUID) -> auto-generate and persist. -func (c *Config) ClusterUUID() string { - // Use value loaded into options only if it is persisted in the current options.yml. - // This avoids tests (or defaults) loading a UUID from an unrelated file path. - if c.options.ClusterUUID != "" { - // Respect explicit CLI value if provided. - if c.cliCtx != nil && c.cliCtx.IsSet("cluster-uuid") { - return c.options.ClusterUUID - } - // Otherwise, only trust a persisted value from the current options.yml. - if fs.FileExists(c.OptionsYaml()) { - return c.options.ClusterUUID - } - } - - // Generate, persist, and cache in memory if still empty. - id := rnd.UUID() - c.options.ClusterUUID = id - - if err := c.saveClusterUUID(id); err != nil { - log.Warnf("config: failed to persist ClusterUUID to %s (%s)", c.OptionsYaml(), err) - } - - return id -} - -// PortalUrl returns the URL of the cluster portal server, if configured. +// PortalUrl returns the URL of the cluster management portal server, if configured. func (c *Config) PortalUrl() string { return c.options.PortalUrl } @@ -85,6 +53,38 @@ func (c *Config) JoinToken() string { } } +// ClusterUUID returns a stable UUIDv4 that uniquely identifies the Portal. +// Precedence: env PHOTOPRISM_CLUSTER_UUID -> options.yml (ClusterUUID) -> auto-generate and persist. +func (c *Config) ClusterUUID() string { + // Use value loaded into options only if it is persisted in the current options.yml. + // This avoids tests (or defaults) loading a UUID from an unrelated file path. + if c.options.ClusterUUID != "" { + // Respect explicit CLI value if provided. + if c.cliCtx != nil && c.cliCtx.IsSet("cluster-uuid") { + return c.options.ClusterUUID + } + // Otherwise, only trust a persisted value from the current options.yml. + if fs.FileExists(c.OptionsYaml()) { + return c.options.ClusterUUID + } + } + + // Generate, persist, and cache in memory if still empty. + id := rnd.UUID() + c.options.ClusterUUID = id + + if err := c.saveClusterUUID(id); err != nil { + log.Warnf("config: failed to persist ClusterUUID to %s (%s)", c.OptionsYaml(), err) + } + + return id +} + +// ClusterDomain returns the cluster DOMAIN (lowercase DNS name; 1–63 chars). +func (c *Config) ClusterDomain() string { + return c.options.ClusterDomain +} + // NodeName returns the cluster node NAME (unique in cluster domain; [a-z0-9-]{1,32}). func (c *Config) NodeName() string { return clean.TypeLowerDash(c.options.NodeName) diff --git a/internal/config/flags.go b/internal/config/flags.go index c05ce3ce0..0eac5401b 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -664,28 +664,25 @@ var Flags = CliFlags{ EnvVars: EnvVars("CORS_METHODS"), Value: header.DefaultAccessControlAllowMethods, }}, { - Flag: &cli.StringFlag{ - Name: "cluster-domain", - Usage: "cluster `DOMAIN` (lowercase DNS name; 1–63 chars)", - EnvVars: EnvVars("CLUSTER_DOMAIN"), - }}, { - Flag: &cli.StringFlag{ - Name: "cluster-uuid", - Usage: "cluster `UUID` (v4) to scope per-node credentials", - EnvVars: EnvVars("CLUSTER_UUID"), - Hidden: true, - }}, { Flag: &cli.StringFlag{ Name: "portal-url", - Usage: "base `URL` of the cluster portal (e.g. https://portal.example.com)", + Usage: "base `URL` of the cluster management portal (e.g. https://portal.example.com)", EnvVars: EnvVars("PORTAL_URL"), - Hidden: true, }}, { Flag: &cli.StringFlag{ Name: "join-token", Usage: "secret `TOKEN` required to join the cluster", EnvVars: EnvVars("JOIN_TOKEN"), - Hidden: true, + }}, { + Flag: &cli.StringFlag{ + Name: "cluster-uuid", + Usage: "cluster `UUID` (v4) to scope node credentials", + EnvVars: EnvVars("CLUSTER_UUID"), + }}, { + Flag: &cli.StringFlag{ + Name: "cluster-domain", + Usage: "cluster `DOMAIN` (lowercase DNS name; 1–63 chars)", + EnvVars: EnvVars("CLUSTER_DOMAIN"), }}, { Flag: &cli.StringFlag{ Name: "node-name", diff --git a/internal/config/options.go b/internal/config/options.go index 70e8bb4c3..f74a9fc3b 100644 --- a/internal/config/options.go +++ b/internal/config/options.go @@ -142,10 +142,10 @@ type Options struct { CORSOrigin string `yaml:"CORSOrigin" json:"-" flag:"cors-origin"` CORSHeaders string `yaml:"CORSHeaders" json:"-" flag:"cors-headers"` CORSMethods string `yaml:"CORSMethods" json:"-" flag:"cors-methods"` - ClusterDomain string `yaml:"ClusterDomain" json:"-" flag:"cluster-domain"` - ClusterUUID string `yaml:"ClusterUUID" json:"-" flag:"cluster-uuid"` PortalUrl string `yaml:"PortalUrl" json:"-" flag:"portal-url"` JoinToken string `yaml:"JoinToken" json:"-" flag:"join-token"` + ClusterUUID string `yaml:"ClusterUUID" json:"-" flag:"cluster-uuid"` + ClusterDomain string `yaml:"ClusterDomain" json:"-" flag:"cluster-domain"` NodeName string `yaml:"NodeName" json:"-" flag:"node-name"` NodeRole string `yaml:"NodeRole" json:"-" flag:"node-role"` NodeID string `yaml:"NodeID" json:"-" flag:"node-id"` diff --git a/internal/config/report.go b/internal/config/report.go index 6912fe4e6..38bb049b0 100644 --- a/internal/config/report.go +++ b/internal/config/report.go @@ -162,12 +162,12 @@ func (c *Config) Report() (rows [][]string, cols []string) { {"site-preview", c.SitePreview()}, // Cluster Configuration. - {"cluster-domain", c.ClusterDomain()}, - {"cluster-uuid", c.ClusterUUID()}, {"portal-url", c.PortalUrl()}, {"portal-config-path", c.PortalConfigPath()}, {"portal-theme-path", c.PortalThemePath()}, {"join-token", fmt.Sprintf("%s", strings.Repeat("*", utf8.RuneCountInString(c.JoinToken())))}, + {"cluster-uuid", c.ClusterUUID()}, + {"cluster-domain", c.ClusterDomain()}, {"node-name", c.NodeName()}, {"node-role", c.NodeRole()}, {"node-id", c.NodeID()}, diff --git a/internal/config/report_sections.go b/internal/config/report_sections.go index 6b199123c..e2a8c5bc8 100644 --- a/internal/config/report_sections.go +++ b/internal/config/report_sections.go @@ -25,7 +25,7 @@ var OptionsReportSections = []ReportSection{ {Start: "PHOTOPRISM_READONLY", Title: "Feature Flags"}, {Start: "PHOTOPRISM_DEFAULT_LOCALE", Title: "Customization"}, {Start: "PHOTOPRISM_SITE_URL", Title: "Site Information"}, - {Start: "PHOTOPRISM_CLUSTER_DOMAIN", Title: "Cluster Configuration"}, + {Start: "PHOTOPRISM_PORTAL_URL", Title: "Cluster Configuration"}, {Start: "PHOTOPRISM_HTTPS_PROXY", Title: "Proxy Server"}, {Start: "PHOTOPRISM_DISABLE_TLS", Title: "Web Server"}, {Start: "PHOTOPRISM_DATABASE_DRIVER", Title: "Database Connection"}, @@ -52,7 +52,7 @@ var YamlReportSections = []ReportSection{ {Start: "ReadOnly", Title: "Feature Flags"}, {Start: "DefaultLocale", Title: "Customization"}, {Start: "SiteUrl", Title: "Site Information"}, - {Start: "ClusterDomain", Title: "Cluster Configuration"}, + {Start: "PortalUrl", Title: "Cluster Configuration"}, {Start: "HttpsProxy", Title: "Proxy Server"}, {Start: "DisableTLS", Title: "Web Server"}, {Start: "DatabaseDriver", Title: "Database Connection"},