summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2020-10-19 22:03:08 +0100
committerGitHub <noreply@github.com>2020-10-19 17:03:08 -0400
commit2f1353a2f33762e10a304cbebf3a6a8d0381d316 (patch)
treeb345bf060a107341c64447f7132d9e2b8d37a7b3
parent3ddf3f93d6346ac9440a7a571faea4b5c1c329be (diff)
downloadgitea-2f1353a2f33762e10a304cbebf3a6a8d0381d316.tar.gz
gitea-2f1353a2f33762e10a304cbebf3a6a8d0381d316.zip
Move install pages out of main macaron routes (#13195)
* Move install pages out of main macaron loop Signed-off-by: Andrew Thornton <art27@cantab.net> * Update templates/post-install.tmpl Co-authored-by: Lauris BH <lauris@nix.lv> * remove prefetch Signed-off-by: Andrew Thornton <art27@cantab.net>
-rw-r--r--cmd/web.go135
-rw-r--r--cmd/web_graceful.go6
-rw-r--r--modules/context/auth.go6
-rw-r--r--modules/graceful/manager.go2
-rw-r--r--modules/graceful/server.go2
-rw-r--r--routers/init.go114
-rw-r--r--routers/install.go36
-rw-r--r--routers/routes/routes.go9
-rw-r--r--templates/install.tmpl3
-rw-r--r--templates/post-install.tmpl24
10 files changed, 228 insertions, 109 deletions
diff --git a/cmd/web.go b/cmd/web.go
index 92d4b11b69..e16d1afb53 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -19,6 +19,8 @@ import (
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/routes"
+ "gitea.com/macaron/macaron"
+
context2 "github.com/gorilla/context"
"github.com/unknwon/com"
"github.com/urfave/cli"
@@ -114,6 +116,39 @@ func runWeb(ctx *cli.Context) error {
setting.WritePIDFile = true
}
+ // Flag for port number in case first time run conflict.
+ if ctx.IsSet("port") {
+ if err := setPort(ctx.String("port")); err != nil {
+ return err
+ }
+ }
+
+ // Perform pre-initialization
+ needsInstall := routers.PreInstallInit(graceful.GetManager().HammerContext())
+ if needsInstall {
+ m := routes.NewMacaron()
+ routes.RegisterInstallRoute(m)
+ err := listen(m, false)
+ select {
+ case <-graceful.GetManager().IsShutdown():
+ <-graceful.GetManager().Done()
+ log.Info("PID: %d Gitea Web Finished", os.Getpid())
+ log.Close()
+ return err
+ default:
+ }
+ } else {
+ NoInstallListener()
+ }
+
+ if setting.EnablePprof {
+ go func() {
+ log.Info("Starting pprof server on localhost:6060")
+ log.Info("%v", http.ListenAndServe("localhost:6060", nil))
+ }()
+ }
+
+ log.Info("Global init")
// Perform global initialization
routers.GlobalInit(graceful.GetManager().HammerContext())
@@ -121,41 +156,49 @@ func runWeb(ctx *cli.Context) error {
m := routes.NewMacaron()
routes.RegisterRoutes(m)
- // Flag for port number in case first time run conflict.
- if ctx.IsSet("port") {
- setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, ctx.String("port"), 1)
- setting.HTTPPort = ctx.String("port")
+ err := listen(m, true)
+ <-graceful.GetManager().Done()
+ log.Info("PID: %d Gitea Web Finished", os.Getpid())
+ log.Close()
+ return err
+}
- switch setting.Protocol {
- case setting.UnixSocket:
- case setting.FCGI:
- case setting.FCGIUnix:
- default:
- // Save LOCAL_ROOT_URL if port changed
- cfg := ini.Empty()
- if com.IsFile(setting.CustomConf) {
- // Keeps custom settings if there is already something.
- if err := cfg.Append(setting.CustomConf); err != nil {
- return fmt.Errorf("Failed to load custom conf '%s': %v", setting.CustomConf, err)
- }
- }
+func setPort(port string) error {
+ setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, port, 1)
+ setting.HTTPPort = port
- defaultLocalURL := string(setting.Protocol) + "://"
- if setting.HTTPAddr == "0.0.0.0" {
- defaultLocalURL += "localhost"
- } else {
- defaultLocalURL += setting.HTTPAddr
+ switch setting.Protocol {
+ case setting.UnixSocket:
+ case setting.FCGI:
+ case setting.FCGIUnix:
+ default:
+ // Save LOCAL_ROOT_URL if port changed
+ cfg := ini.Empty()
+ if com.IsFile(setting.CustomConf) {
+ // Keeps custom settings if there is already something.
+ if err := cfg.Append(setting.CustomConf); err != nil {
+ return fmt.Errorf("Failed to load custom conf '%s': %v", setting.CustomConf, err)
}
- defaultLocalURL += ":" + setting.HTTPPort + "/"
+ }
+
+ defaultLocalURL := string(setting.Protocol) + "://"
+ if setting.HTTPAddr == "0.0.0.0" {
+ defaultLocalURL += "localhost"
+ } else {
+ defaultLocalURL += setting.HTTPAddr
+ }
+ defaultLocalURL += ":" + setting.HTTPPort + "/"
- cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
+ cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
- if err := cfg.SaveTo(setting.CustomConf); err != nil {
- return fmt.Errorf("Error saving generated JWT Secret to custom config: %v", err)
- }
+ if err := cfg.SaveTo(setting.CustomConf); err != nil {
+ return fmt.Errorf("Error saving generated JWT Secret to custom config: %v", err)
}
}
+ return nil
+}
+func listen(m *macaron.Macaron, handleRedirector bool) error {
listenAddr := setting.HTTPAddr
if setting.Protocol != setting.UnixSocket && setting.Protocol != setting.FCGIUnix {
listenAddr = net.JoinHostPort(listenAddr, setting.HTTPPort)
@@ -166,37 +209,40 @@ func runWeb(ctx *cli.Context) error {
log.Info("LFS server enabled")
}
- if setting.EnablePprof {
- go func() {
- log.Info("Starting pprof server on localhost:6060")
- log.Info("%v", http.ListenAndServe("localhost:6060", nil))
- }()
- }
-
var err error
switch setting.Protocol {
case setting.HTTP:
- NoHTTPRedirector()
+ if handleRedirector {
+ NoHTTPRedirector()
+ }
err = runHTTP("tcp", listenAddr, context2.ClearHandler(m))
case setting.HTTPS:
if setting.EnableLetsEncrypt {
err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, context2.ClearHandler(m))
break
}
- if setting.RedirectOtherPort {
- go runHTTPRedirector()
- } else {
- NoHTTPRedirector()
+ if handleRedirector {
+ if setting.RedirectOtherPort {
+ go runHTTPRedirector()
+ } else {
+ NoHTTPRedirector()
+ }
}
err = runHTTPS("tcp", listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m))
case setting.FCGI:
- NoHTTPRedirector()
+ if handleRedirector {
+ NoHTTPRedirector()
+ }
err = runFCGI("tcp", listenAddr, context2.ClearHandler(m))
case setting.UnixSocket:
- NoHTTPRedirector()
+ if handleRedirector {
+ NoHTTPRedirector()
+ }
err = runHTTP("unix", listenAddr, context2.ClearHandler(m))
case setting.FCGIUnix:
- NoHTTPRedirector()
+ if handleRedirector {
+ NoHTTPRedirector()
+ }
err = runFCGI("unix", listenAddr, context2.ClearHandler(m))
default:
log.Fatal("Invalid protocol: %s", setting.Protocol)
@@ -206,8 +252,5 @@ func runWeb(ctx *cli.Context) error {
log.Critical("Failed to start server: %v", err)
}
log.Info("HTTP Listener: %s Closed", listenAddr)
- <-graceful.GetManager().Done()
- log.Info("PID: %d Gitea Web Finished", os.Getpid())
- log.Close()
- return nil
+ return err
}
diff --git a/cmd/web_graceful.go b/cmd/web_graceful.go
index f3c41766af..9e039de699 100644
--- a/cmd/web_graceful.go
+++ b/cmd/web_graceful.go
@@ -37,6 +37,12 @@ func NoMainListener() {
graceful.GetManager().InformCleanup()
}
+// NoInstallListener tells our cleanup routine that we will not be using a possibly provided listener
+// for our install HTTP/HTTPS service
+func NoInstallListener() {
+ graceful.GetManager().InformCleanup()
+}
+
func runFCGI(network, listenAddr string, m http.Handler) error {
// This needs to handle stdin as fcgi point
fcgiServer := graceful.NewServer(network, listenAddr)
diff --git a/modules/context/auth.go b/modules/context/auth.go
index 00a7032e27..02248384e1 100644
--- a/modules/context/auth.go
+++ b/modules/context/auth.go
@@ -26,12 +26,6 @@ type ToggleOptions struct {
// Toggle returns toggle options as middleware
func Toggle(options *ToggleOptions) macaron.Handler {
return func(ctx *Context) {
- // Cannot view any page before installation.
- if !setting.InstallLock {
- ctx.Redirect(setting.AppSubURL + "/install")
- return
- }
-
isAPIPath := auth.IsAPIPath(ctx.Req.URL.Path)
// Check prohibit login users.
diff --git a/modules/graceful/manager.go b/modules/graceful/manager.go
index 6b134e7d0c..903d05ed21 100644
--- a/modules/graceful/manager.go
+++ b/modules/graceful/manager.go
@@ -31,7 +31,7 @@ const (
//
// If you add an additional place you must increment this number
// and add a function to call manager.InformCleanup if it's not going to be used
-const numberOfServersToCreate = 3
+const numberOfServersToCreate = 4
// Manager represents the graceful server manager interface
var manager *Manager
diff --git a/modules/graceful/server.go b/modules/graceful/server.go
index db73174ac1..e7394f349e 100644
--- a/modules/graceful/server.go
+++ b/modules/graceful/server.go
@@ -162,7 +162,7 @@ func (srv *Server) Serve(serve ServeFunction) error {
srv.setState(stateTerminate)
GetManager().ServerDone()
// use of closed means that the listeners are closed - i.e. we should be shutting down - return nil
- if err != nil && strings.Contains(err.Error(), "use of closed") {
+ if err == nil || strings.Contains(err.Error(), "use of closed") || strings.Contains(err.Error(), "http: Server closed") {
return nil
}
return err
diff --git a/routers/init.go b/routers/init.go
index 793033f4a4..702acb7260 100644
--- a/routers/init.go
+++ b/routers/init.go
@@ -117,9 +117,46 @@ func InitLocales() {
})
}
+// PreInstallInit preloads the configuration to check if we need to run install
+func PreInstallInit(ctx context.Context) bool {
+ setting.NewContext()
+ if !setting.InstallLock {
+ log.Trace("AppPath: %s", setting.AppPath)
+ log.Trace("AppWorkPath: %s", setting.AppWorkPath)
+ log.Trace("Custom path: %s", setting.CustomPath)
+ log.Trace("Log path: %s", setting.LogRootPath)
+ log.Trace("Preparing to run install page")
+ InitLocales()
+ if setting.EnableSQLite3 {
+ log.Info("SQLite3 Supported")
+ }
+ setting.InitDBConfig()
+ svg.Init()
+ }
+
+ return !setting.InstallLock
+}
+
+// PostInstallInit rereads the settings and starts up the database
+func PostInstallInit(ctx context.Context) {
+ setting.NewContext()
+ setting.InitDBConfig()
+ if setting.InstallLock {
+ if err := initDBEngine(ctx); err == nil {
+ log.Info("ORM engine initialization successful!")
+ } else {
+ log.Fatal("ORM engine initialization failed: %v", err)
+ }
+ svg.Init()
+ }
+}
+
// GlobalInit is for global configuration reload-able.
func GlobalInit(ctx context.Context) {
setting.NewContext()
+ if !setting.InstallLock {
+ log.Fatal("Gitea is not installed")
+ }
if err := git.Init(ctx); err != nil {
log.Fatal("Git module init failed: %v", err)
}
@@ -134,59 +171,50 @@ func GlobalInit(ctx context.Context) {
NewServices()
- if setting.InstallLock {
- highlight.NewContext()
- external.RegisterParsers()
- markup.Init()
- if err := initDBEngine(ctx); err == nil {
- log.Info("ORM engine initialization successful!")
- } else {
- log.Fatal("ORM engine initialization failed: %v", err)
- }
+ highlight.NewContext()
+ external.RegisterParsers()
+ markup.Init()
+ if err := initDBEngine(ctx); err == nil {
+ log.Info("ORM engine initialization successful!")
+ } else {
+ log.Fatal("ORM engine initialization failed: %v", err)
+ }
- if err := models.InitOAuth2(); err != nil {
- log.Fatal("Failed to initialize OAuth2 support: %v", err)
- }
+ if err := models.InitOAuth2(); err != nil {
+ log.Fatal("Failed to initialize OAuth2 support: %v", err)
+ }
- models.NewRepoContext()
+ models.NewRepoContext()
- // Booting long running goroutines.
- cron.NewContext()
- issue_indexer.InitIssueIndexer(false)
- code_indexer.Init()
- if err := stats_indexer.Init(); err != nil {
- log.Fatal("Failed to initialize repository stats indexer queue: %v", err)
- }
- mirror_service.InitSyncMirrors()
- webhook.InitDeliverHooks()
- if err := pull_service.Init(); err != nil {
- log.Fatal("Failed to initialize test pull requests queue: %v", err)
- }
- if err := task.Init(); err != nil {
- log.Fatal("Failed to initialize task scheduler: %v", err)
- }
- eventsource.GetManager().Init()
+ // Booting long running goroutines.
+ cron.NewContext()
+ issue_indexer.InitIssueIndexer(false)
+ code_indexer.Init()
+ if err := stats_indexer.Init(); err != nil {
+ log.Fatal("Failed to initialize repository stats indexer queue: %v", err)
}
+ mirror_service.InitSyncMirrors()
+ webhook.InitDeliverHooks()
+ if err := pull_service.Init(); err != nil {
+ log.Fatal("Failed to initialize test pull requests queue: %v", err)
+ }
+ if err := task.Init(); err != nil {
+ log.Fatal("Failed to initialize task scheduler: %v", err)
+ }
+ eventsource.GetManager().Init()
+
if setting.EnableSQLite3 {
log.Info("SQLite3 Supported")
}
checkRunMode()
- // Now because Install will re-run GlobalInit once it has set InstallLock
- // we can't tell if the ssh port will remain unused until that's done.
- // However, see FIXME comment in install.go
- if setting.InstallLock {
- if setting.SSH.StartBuiltinServer {
- ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
- log.Info("SSH server started on %s:%d. Cipher list (%v), key exchange algorithms (%v), MACs (%v)", setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
- } else {
- ssh.Unused()
- }
- }
-
- if setting.InstallLock {
- sso.Init()
+ if setting.SSH.StartBuiltinServer {
+ ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
+ log.Info("SSH server started on %s:%d. Cipher list (%v), key exchange algorithms (%v), MACs (%v)", setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
+ } else {
+ ssh.Unused()
}
+ sso.Init()
svg.Init()
}
diff --git a/routers/install.go b/routers/install.go
index a7fe557748..5d0d089dc0 100644
--- a/routers/install.go
+++ b/routers/install.go
@@ -5,7 +5,7 @@
package routers
import (
- "errors"
+ "net/http"
"os"
"os/exec"
"path/filepath"
@@ -27,13 +27,15 @@ import (
const (
// tplInstall template for installation page
- tplInstall base.TplName = "install"
+ tplInstall base.TplName = "install"
+ tplPostInstall base.TplName = "post-install"
)
// InstallInit prepare for rendering installation page
func InstallInit(ctx *context.Context) {
if setting.InstallLock {
- ctx.NotFound("Install", errors.New("Installation is prohibited"))
+ ctx.Header().Add("Refresh", "1; url="+setting.AppURL+"user/login")
+ ctx.HTML(200, tplPostInstall)
return
}
@@ -357,7 +359,8 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
return
}
- GlobalInit(graceful.GetManager().HammerContext())
+ // Re-read settings
+ PostInstallInit(ctx.Req.Context())
// Create admin account
if len(form.AdminName) > 0 {
@@ -380,6 +383,11 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
u, _ = models.GetUserByName(u.Name)
}
+ days := 86400 * setting.LogInRememberDays
+ ctx.SetCookie(setting.CookieUserName, u.Name, days, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
+ ctx.SetSuperSecureCookie(base.EncodeMD5(u.Rands+u.Passwd),
+ setting.CookieRememberName, u.Name, days, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
+
// Auto-login for admin
if err = ctx.Session.Set("uid", u.ID); err != nil {
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
@@ -397,12 +405,18 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
}
log.Info("First-time run install finished!")
- // FIXME: This isn't really enough to completely take account of new configuration
- // We should really be restarting:
- // - On windows this is probably just a simple restart
- // - On linux we can't just use graceful.RestartProcess() everything that was passed in on LISTEN_FDS
- // (active or not) needs to be passed out and everything new passed out too.
- // This means we need to prevent the cleanup goroutine from running prior to the second GlobalInit
+
ctx.Flash.Success(ctx.Tr("install.install_success"))
- ctx.Redirect(form.AppURL + "user/login")
+
+ ctx.Header().Add("Refresh", "1; url="+setting.AppURL+"user/login")
+ ctx.HTML(200, tplPostInstall)
+
+ // Now get the http.Server from this request and shut it down
+ // NB: This is not our hammerable graceful shutdown this is http.Server.Shutdown
+ srv := ctx.Req.Context().Value(http.ServerContextKey).(*http.Server)
+ go func() {
+ if err := srv.Shutdown(graceful.GetManager().HammerContext()); err != nil {
+ log.Error("Unable to shutdown the install server! Error: %v", err)
+ }
+ }()
}
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index 9f7ff277cf..7f43b3b2b1 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -301,6 +301,15 @@ func NewMacaron() *macaron.Macaron {
return m
}
+// RegisterInstallRoute registers the install routes
+func RegisterInstallRoute(m *macaron.Macaron) {
+ m.Combo("/", routers.InstallInit).Get(routers.Install).
+ Post(binding.BindIgnErr(auth.InstallForm{}), routers.InstallPost)
+ m.NotFound(func(ctx *context.Context) {
+ ctx.Redirect(setting.AppURL, 302)
+ })
+}
+
// RegisterRoutes routes routes to Macaron
func RegisterRoutes(m *macaron.Macaron) {
reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true})
diff --git a/templates/install.tmpl b/templates/install.tmpl
index 27cf1034c5..f0e4680c32 100644
--- a/templates/install.tmpl
+++ b/templates/install.tmpl
@@ -10,7 +10,7 @@
<p>{{.i18n.Tr "install.docker_helper" "https://docs.gitea.io/en-us/install-with-docker/" | Safe}}</p>
- <form class="ui form" action="{{AppSubUrl}}/install" method="post">
+ <form class="ui form" action="{{AppSubUrl}}/" method="post">
<!-- Database Settings -->
<h4 class="ui dividing header">{{.i18n.Tr "install.db_title"}}</h4>
<p>{{.i18n.Tr "install.requite_db_desc"}}</p>
@@ -307,4 +307,5 @@
</div>
</div>
</div>
+<img style="display: none" src="{{StaticUrlPrefix}}/img/loading.png"/>
{{template "base/footer" .}}
diff --git a/templates/post-install.tmpl b/templates/post-install.tmpl
new file mode 100644
index 0000000000..c7886a3263
--- /dev/null
+++ b/templates/post-install.tmpl
@@ -0,0 +1,24 @@
+{{template "base/head" .}}
+<div class="install">
+ <div class="ui container">
+ <div class="ui grid">
+ <div class="sixteen wide column content">
+ <div class="home">
+ <div class="ui stackable middle very relaxed page grid">
+ <div id="repo_migrating" class="sixteen wide center aligned centered column">
+ <div>
+ <img src="{{StaticUrlPrefix}}/img/loading.png"/>
+ </div>
+ </div>
+ </div>
+ <div class="ui stackable middle very relaxed page grid">
+ <div class="sixteen wide center aligned centered column">
+ <p><a href="{{AppUrl}}user/login">{{AppUrl}}user/login</a></p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+{{template "base/footer" .}}