Config: Improve initialization, migrations, and debug logs
This commit is contained in:
parent
5462b1e69e
commit
d67e325854
|
@ -170,6 +170,8 @@ func (c *Config) Propagate() {
|
|||
|
||||
// Init creates directories, parses additional config files, opens a database connection and initializes dependencies.
|
||||
func (c *Config) Init() error {
|
||||
start := time.Now()
|
||||
|
||||
if err := c.CreateDirectories(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -215,7 +217,13 @@ func (c *Config) Init() error {
|
|||
|
||||
c.Propagate()
|
||||
|
||||
return c.connectDb()
|
||||
err := c.connectDb()
|
||||
|
||||
if err == nil {
|
||||
log.Debugf("config: successfully initialized [%s]", time.Since(start))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// initStorage initializes storage directories with a random serial.
|
||||
|
@ -571,7 +579,7 @@ func (c *Config) UpdateHub() {
|
|||
|
||||
// initHub initializes PhotoPrism hub config.
|
||||
func (c *Config) initHub() {
|
||||
c.hub = hub.NewConfig(c.Version(), c.HubConfigFile(), c.serial)
|
||||
c.hub = hub.NewConfig(c.Version(), c.HubConfigFile(), c.serial, c.options.PartnerID)
|
||||
|
||||
if err := c.hub.Load(); err == nil {
|
||||
// Do nothing.
|
||||
|
|
|
@ -64,6 +64,12 @@ var GlobalFlags = []cli.Flag{
|
|||
Usage: "enable experimental features",
|
||||
EnvVar: "PHOTOPRISM_EXPERIMENTAL",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "partner-id",
|
||||
Hidden: true,
|
||||
Usage: "hosting partner id",
|
||||
EnvVar: "PHOTOPRISM_PARTNER_ID",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "config-file, c",
|
||||
Usage: "load config options from `FILENAME`",
|
||||
|
|
|
@ -26,15 +26,16 @@ const (
|
|||
// Options provides a struct in which application configuration is stored.
|
||||
// Application code must use functions to get config options, for two reasons:
|
||||
//
|
||||
// 1. Some options are computed and we don't want to leak implementation details (aims at reducing refactoring overhead).
|
||||
//
|
||||
// 2. Paths might actually be dynamic later (if we build a multi-user version).
|
||||
// 1. We do not want to leak implementation details so refactoring overhead is kept low
|
||||
// 2. Some config values are dynamically generated
|
||||
// 3. Paths may become dynamic too at a later time
|
||||
//
|
||||
// See https://github.com/photoprism/photoprism/issues/50#issuecomment-433856358
|
||||
type Options struct {
|
||||
Name string `json:"-"`
|
||||
Version string `json:"-"`
|
||||
Copyright string `json:"-"`
|
||||
PartnerID string `yaml:"-" json:"-" flag:"partner-id"`
|
||||
AdminPassword string `yaml:"AdminPassword" json:"-" flag:"admin-password"`
|
||||
LogLevel string `yaml:"LogLevel" json:"-" flag:"log-level"`
|
||||
Debug bool `yaml:"Debug" json:"Debug" flag:"debug"`
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// CreateDefaultFixtures inserts default fixtures for test and production.
|
||||
func CreateDefaultFixtures() {
|
||||
CreateUnknownAddress()
|
||||
|
@ -11,8 +15,10 @@ func CreateDefaultFixtures() {
|
|||
CreateUnknownLens()
|
||||
}
|
||||
|
||||
// ResetTestFixtures re-creates registered database tables and inserts test fixtures.
|
||||
// ResetTestFixtures recreates database tables and test fixtures.
|
||||
func ResetTestFixtures() {
|
||||
start := time.Now()
|
||||
|
||||
Entities.Migrate(Db(), false)
|
||||
Entities.WaitForMigration(Db())
|
||||
Entities.Truncate(Db())
|
||||
|
@ -20,4 +26,6 @@ func ResetTestFixtures() {
|
|||
CreateDefaultFixtures()
|
||||
|
||||
CreateTestFixtures()
|
||||
|
||||
log.Debugf("entity: recreated test fixtures [%s]", time.Since(start))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// MigrateDb creates database tables and inserts default fixtures as needed.
|
||||
func MigrateDb(dropDeprecated, runFailed bool) {
|
||||
start := time.Now()
|
||||
|
||||
if dropDeprecated {
|
||||
DeprecatedTables.Drop(Db())
|
||||
}
|
||||
|
@ -10,6 +16,8 @@ func MigrateDb(dropDeprecated, runFailed bool) {
|
|||
Entities.WaitForMigration(Db())
|
||||
|
||||
CreateDefaultFixtures()
|
||||
|
||||
log.Debugf("entity: successfully initialized [%s]", time.Since(start))
|
||||
}
|
||||
|
||||
// InitTestDb connects to and completely initializes the test database incl fixtures.
|
||||
|
|
|
@ -31,10 +31,11 @@ type Config struct {
|
|||
Version string `json:"version" yaml:"Version"`
|
||||
Serial string `json:"serial" yaml:"Serial"`
|
||||
FileName string `json:"-" yaml:"-"`
|
||||
PartnerID string `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
// NewConfig creates a new backend api credentials instance.
|
||||
func NewConfig(version, fileName, serial string) *Config {
|
||||
func NewConfig(version, fileName, serial, partner string) *Config {
|
||||
return &Config{
|
||||
Key: "",
|
||||
Secret: "",
|
||||
|
@ -43,6 +44,7 @@ func NewConfig(version, fileName, serial string) *Config {
|
|||
Version: version,
|
||||
Serial: serial,
|
||||
FileName: fileName,
|
||||
PartnerID: partner,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,12 +142,12 @@ func (c *Config) Refresh() (err error) {
|
|||
if c.Key != "" {
|
||||
url = fmt.Sprintf(ServiceURL+"/%s", c.Key)
|
||||
method = http.MethodPut
|
||||
log.Debugf("getting updated api key for maps & places from %s", ApiHost())
|
||||
log.Debugf("config: requesting updated api key for maps and places")
|
||||
} else {
|
||||
log.Debugf("requesting api key for maps & places from %s", ApiHost())
|
||||
log.Debugf("config: requesting new api key for maps and places")
|
||||
}
|
||||
|
||||
if j, err := json.Marshal(NewRequest(c.Version, c.Serial)); err != nil {
|
||||
if j, err := json.Marshal(NewRequest(c.Version, c.Serial, c.PartnerID)); err != nil {
|
||||
return err
|
||||
} else if req, err = http.NewRequest(method, url, bytes.NewReader(j)); err != nil {
|
||||
return err
|
||||
|
@ -166,7 +168,7 @@ func (c *Config) Refresh() (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
} else if r.StatusCode >= 400 {
|
||||
err = fmt.Errorf("getting api key from %s failed (error %d)", ApiHost(), r.StatusCode)
|
||||
err = fmt.Errorf("fetching api key from %s failed (error %d)", ApiHost(), r.StatusCode)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
func TestConfig_MapKey(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
c := NewConfig("0.0.0", "testdata/new.yml", "zqkunt22r0bewti9")
|
||||
c := NewConfig("0.0.0", "testdata/new.yml", "zqkunt22r0bewti9", "test")
|
||||
assert.Equal(t, "", c.MapKey())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ type Feedback struct {
|
|||
UserEmail string `json:"UserEmail"`
|
||||
UserAgent string `json:"UserAgent"`
|
||||
ApiKey string `json:"ApiKey"`
|
||||
PartnerID string `json:"PartnerID"`
|
||||
ClientVersion string `json:"ClientVersion"`
|
||||
ClientSerial string `json:"ClientSerial"`
|
||||
ClientOS string `json:"ClientOS"`
|
||||
|
@ -30,8 +31,9 @@ type Feedback struct {
|
|||
}
|
||||
|
||||
// NewFeedback creates a new hub feedback instance.
|
||||
func NewFeedback(version, serial string) *Feedback {
|
||||
func NewFeedback(version, serial, partner string) *Feedback {
|
||||
return &Feedback{
|
||||
PartnerID: partner,
|
||||
ClientVersion: version,
|
||||
ClientSerial: serial,
|
||||
ClientOS: runtime.GOOS,
|
||||
|
@ -41,7 +43,7 @@ func NewFeedback(version, serial string) *Feedback {
|
|||
}
|
||||
|
||||
func (c *Config) SendFeedback(f form.Feedback) (err error) {
|
||||
feedback := NewFeedback(c.Version, c.Serial)
|
||||
feedback := NewFeedback(c.Version, c.Serial, c.PartnerID)
|
||||
feedback.Category = f.Category
|
||||
feedback.Subject = txt.Shorten(f.Message, 50, "...")
|
||||
feedback.Message = f.Message
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
func TestNewFeedback(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
feedback := NewFeedback("xxx", "zqkunt22r0bewti9")
|
||||
feedback := NewFeedback("xxx", "zqkunt22r0bewti9", "test")
|
||||
assert.Equal(t, "xxx", feedback.ClientVersion)
|
||||
assert.Equal(t, "zqkunt22r0bewti9", feedback.ClientSerial)
|
||||
})
|
||||
|
@ -17,7 +17,7 @@ func TestNewFeedback(t *testing.T) {
|
|||
|
||||
func TestSendFeedback(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
c := NewConfig("0.0.0", "testdata/new.yml", "zqkunt22r0bewti9")
|
||||
c := NewConfig("0.0.0", "testdata/new.yml", "zqkunt22r0bewti9", "test")
|
||||
|
||||
feedback := Feedback{
|
||||
Category: "Bug Report",
|
||||
|
|
|
@ -49,13 +49,13 @@ func Token(size uint) string {
|
|||
}
|
||||
|
||||
func TestNewConfig(t *testing.T) {
|
||||
c := NewConfig("0.0.0", "testdata/new.yml", "zqkunt22r0bewti9")
|
||||
c := NewConfig("0.0.0", "testdata/new.yml", "zqkunt22r0bewti9", "test")
|
||||
|
||||
assert.IsType(t, &Config{}, c)
|
||||
}
|
||||
|
||||
func TestNewRequest(t *testing.T) {
|
||||
r := NewRequest("0.0.0", "zqkunt22r0bewti9")
|
||||
r := NewRequest("0.0.0", "zqkunt22r0bewti9", "test")
|
||||
|
||||
assert.IsType(t, &Request{}, r)
|
||||
|
||||
|
@ -72,7 +72,7 @@ func TestConfig_Refresh(t *testing.T) {
|
|||
t.Run("success", func(t *testing.T) {
|
||||
fileName := fmt.Sprintf("testdata/hub.%s.yml", Token(8))
|
||||
|
||||
c := NewConfig("0.0.0", fileName, "zqkunt22r0bewti9")
|
||||
c := NewConfig("0.0.0", fileName, "zqkunt22r0bewti9", "test")
|
||||
|
||||
if err := c.Refresh(); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -122,7 +122,7 @@ func TestConfig_Refresh(t *testing.T) {
|
|||
|
||||
func TestConfig_DecodeSession(t *testing.T) {
|
||||
t.Run("hub3.yml", func(t *testing.T) {
|
||||
c := NewConfig("0.0.0", "testdata/hub3.yml", "zqkunt22r0bewti9")
|
||||
c := NewConfig("0.0.0", "testdata/hub3.yml", "zqkunt22r0bewti9", "test")
|
||||
|
||||
err := c.Load()
|
||||
|
||||
|
@ -138,7 +138,7 @@ func TestConfig_DecodeSession(t *testing.T) {
|
|||
|
||||
func TestConfig_Load(t *testing.T) {
|
||||
t.Run("hub1.yml", func(t *testing.T) {
|
||||
c := NewConfig("0.0.0", "testdata/hub1.yml", "zqkunt22r0bewti9")
|
||||
c := NewConfig("0.0.0", "testdata/hub1.yml", "zqkunt22r0bewti9", "test")
|
||||
|
||||
if err := c.Load(); err != nil {
|
||||
t.Logf(err.Error())
|
||||
|
@ -151,7 +151,7 @@ func TestConfig_Load(t *testing.T) {
|
|||
assert.Equal(t, "0.0.0", c.Version)
|
||||
})
|
||||
t.Run("hub2.yml", func(t *testing.T) {
|
||||
c := NewConfig("0.0.0", "testdata/hub2.yml", "zqkunt22r0bewti9")
|
||||
c := NewConfig("0.0.0", "testdata/hub2.yml", "zqkunt22r0bewti9", "test")
|
||||
|
||||
if err := c.Load(); err != nil {
|
||||
t.Logf(err.Error())
|
||||
|
@ -164,7 +164,7 @@ func TestConfig_Load(t *testing.T) {
|
|||
assert.Equal(t, "200925-f8e2b580-Darwin-i386-DEBUG", c.Version)
|
||||
})
|
||||
t.Run("not existing filename", func(t *testing.T) {
|
||||
c := NewConfig("0.0.0", "testdata/hub_xxx.yml", "zqkunt22r0bewti9")
|
||||
c := NewConfig("0.0.0", "testdata/hub_xxx.yml", "zqkunt22r0bewti9", "test")
|
||||
|
||||
if err := c.Load(); err == nil {
|
||||
t.Fatal("file should not exist")
|
||||
|
@ -180,7 +180,7 @@ func TestConfig_Save(t *testing.T) {
|
|||
t.Run("existing filename", func(t *testing.T) {
|
||||
assert.FileExists(t, "testdata/hub1.yml")
|
||||
|
||||
c := NewConfig("0.0.0", "testdata/hub1.yml", "zqkunt22r0bewti9")
|
||||
c := NewConfig("0.0.0", "testdata/hub1.yml", "zqkunt22r0bewti9", "test")
|
||||
|
||||
if err := c.Load(); err != nil {
|
||||
t.Logf(err.Error())
|
||||
|
@ -219,7 +219,7 @@ func TestConfig_Save(t *testing.T) {
|
|||
assert.Equal(t, "0.0.0", c.Version)
|
||||
})
|
||||
t.Run("not existing filename", func(t *testing.T) {
|
||||
c := NewConfig("0.0.0", "testdata/hub_new.yml", "zqkunt22r0bewti9")
|
||||
c := NewConfig("0.0.0", "testdata/hub_new.yml", "zqkunt22r0bewti9", "test")
|
||||
c.Key = "F60F5B25D59C397989E3CD374F81CDD7710A4FCA"
|
||||
c.Secret = "foo"
|
||||
c.Session = "bar"
|
||||
|
|
|
@ -9,6 +9,7 @@ var ServiceURL = "https://hub.photoprism.app/v1/hello"
|
|||
|
||||
// Request represents basic environment specs for debugging.
|
||||
type Request struct {
|
||||
PartnerID string `json:"PartnerID"`
|
||||
ClientVersion string `json:"ClientVersion"`
|
||||
ClientSerial string `json:"ClientSerial"`
|
||||
ClientOS string `json:"ClientOS"`
|
||||
|
@ -17,8 +18,9 @@ type Request struct {
|
|||
}
|
||||
|
||||
// NewRequest creates a new backend key request instance.
|
||||
func NewRequest(version, serial string) *Request {
|
||||
func NewRequest(version, serial, partner string) *Request {
|
||||
return &Request{
|
||||
PartnerID: partner,
|
||||
ClientVersion: version,
|
||||
ClientSerial: serial,
|
||||
ClientOS: runtime.GOOS,
|
||||
|
|
|
@ -17,9 +17,8 @@ type MigrationMap map[string]Migration
|
|||
// Existing finds and returns previously executed database schema migrations.
|
||||
func Existing(db *gorm.DB) MigrationMap {
|
||||
result := make(MigrationMap)
|
||||
dialect := db.Dialect().GetName()
|
||||
|
||||
stmt := db.Model(Migration{}).Where("dialect = ?", dialect)
|
||||
stmt := db.Model(Migration{})
|
||||
stmt = stmt.Select("id, dialect, error, source, started_at, finished_at")
|
||||
|
||||
rows, err := stmt.Rows()
|
||||
|
@ -52,7 +51,11 @@ func (m *Migrations) Start(db *gorm.DB, runFailed bool) {
|
|||
// Find previously executed migrations.
|
||||
executed := Existing(db)
|
||||
|
||||
if prev := len(executed); prev == 0 {
|
||||
log.Infof("migrate: found no previous migrations")
|
||||
} else {
|
||||
log.Debugf("migrate: found %s", english.Plural(len(executed), "previous migration", "previous migrations"))
|
||||
}
|
||||
|
||||
for _, migration := range *m {
|
||||
start := time.Now()
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-contrib/gzip"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -21,6 +22,8 @@ func Start(ctx context.Context, conf *config.Config) {
|
|||
}
|
||||
}()
|
||||
|
||||
start := time.Now()
|
||||
|
||||
// Set HTTP server mode.
|
||||
if conf.HttpMode() != "" {
|
||||
gin.SetMode(conf.HttpMode())
|
||||
|
@ -76,6 +79,8 @@ func Start(ctx context.Context, conf *config.Config) {
|
|||
Handler: router,
|
||||
}
|
||||
|
||||
log.Debugf("http: successfully initialized [%s]", time.Since(start))
|
||||
|
||||
// Start HTTP server.
|
||||
go func() {
|
||||
log.Infof("http: starting web server at %s", server.Addr)
|
||||
|
|
Loading…
Reference in a new issue