Skip to content

Commit 2f1353a

Browse files
authoredOct 19, 2020
Move install pages out of main macaron routes (#13195)
* Move install pages out of main macaron loop Signed-off-by: Andrew Thornton <[email protected]> * Update templates/post-install.tmpl Co-authored-by: Lauris BH <[email protected]> * remove prefetch Signed-off-by: Andrew Thornton <[email protected]>
1 parent 3ddf3f9 commit 2f1353a

File tree

10 files changed

+228
-109
lines changed

10 files changed

+228
-109
lines changed
 

‎cmd/web.go

Lines changed: 89 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
"code.gitea.io/gitea/routers"
2020
"code.gitea.io/gitea/routers/routes"
2121

22+
"gitea.com/macaron/macaron"
23+
2224
context2 "github.com/gorilla/context"
2325
"github.com/unknwon/com"
2426
"github.com/urfave/cli"
@@ -114,48 +116,89 @@ func runWeb(ctx *cli.Context) error {
114116
setting.WritePIDFile = true
115117
}
116118

119+
// Flag for port number in case first time run conflict.
120+
if ctx.IsSet("port") {
121+
if err := setPort(ctx.String("port")); err != nil {
122+
return err
123+
}
124+
}
125+
126+
// Perform pre-initialization
127+
needsInstall := routers.PreInstallInit(graceful.GetManager().HammerContext())
128+
if needsInstall {
129+
m := routes.NewMacaron()
130+
routes.RegisterInstallRoute(m)
131+
err := listen(m, false)
132+
select {
133+
case <-graceful.GetManager().IsShutdown():
134+
<-graceful.GetManager().Done()
135+
log.Info("PID: %d Gitea Web Finished", os.Getpid())
136+
log.Close()
137+
return err
138+
default:
139+
}
140+
} else {
141+
NoInstallListener()
142+
}
143+
144+
if setting.EnablePprof {
145+
go func() {
146+
log.Info("Starting pprof server on localhost:6060")
147+
log.Info("%v", http.ListenAndServe("localhost:6060", nil))
148+
}()
149+
}
150+
151+
log.Info("Global init")
117152
// Perform global initialization
118153
routers.GlobalInit(graceful.GetManager().HammerContext())
119154

120155
// Set up Macaron
121156
m := routes.NewMacaron()
122157
routes.RegisterRoutes(m)
123158

124-
// Flag for port number in case first time run conflict.
125-
if ctx.IsSet("port") {
126-
setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, ctx.String("port"), 1)
127-
setting.HTTPPort = ctx.String("port")
159+
err := listen(m, true)
160+
<-graceful.GetManager().Done()
161+
log.Info("PID: %d Gitea Web Finished", os.Getpid())
162+
log.Close()
163+
return err
164+
}
128165

129-
switch setting.Protocol {
130-
case setting.UnixSocket:
131-
case setting.FCGI:
132-
case setting.FCGIUnix:
133-
default:
134-
// Save LOCAL_ROOT_URL if port changed
135-
cfg := ini.Empty()
136-
if com.IsFile(setting.CustomConf) {
137-
// Keeps custom settings if there is already something.
138-
if err := cfg.Append(setting.CustomConf); err != nil {
139-
return fmt.Errorf("Failed to load custom conf '%s': %v", setting.CustomConf, err)
140-
}
141-
}
166+
func setPort(port string) error {
167+
setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, port, 1)
168+
setting.HTTPPort = port
142169

143-
defaultLocalURL := string(setting.Protocol) + "://"
144-
if setting.HTTPAddr == "0.0.0.0" {
145-
defaultLocalURL += "localhost"
146-
} else {
147-
defaultLocalURL += setting.HTTPAddr
170+
switch setting.Protocol {
171+
case setting.UnixSocket:
172+
case setting.FCGI:
173+
case setting.FCGIUnix:
174+
default:
175+
// Save LOCAL_ROOT_URL if port changed
176+
cfg := ini.Empty()
177+
if com.IsFile(setting.CustomConf) {
178+
// Keeps custom settings if there is already something.
179+
if err := cfg.Append(setting.CustomConf); err != nil {
180+
return fmt.Errorf("Failed to load custom conf '%s': %v", setting.CustomConf, err)
148181
}
149-
defaultLocalURL += ":" + setting.HTTPPort + "/"
182+
}
183+
184+
defaultLocalURL := string(setting.Protocol) + "://"
185+
if setting.HTTPAddr == "0.0.0.0" {
186+
defaultLocalURL += "localhost"
187+
} else {
188+
defaultLocalURL += setting.HTTPAddr
189+
}
190+
defaultLocalURL += ":" + setting.HTTPPort + "/"
150191

151-
cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
192+
cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
152193

153-
if err := cfg.SaveTo(setting.CustomConf); err != nil {
154-
return fmt.Errorf("Error saving generated JWT Secret to custom config: %v", err)
155-
}
194+
if err := cfg.SaveTo(setting.CustomConf); err != nil {
195+
return fmt.Errorf("Error saving generated JWT Secret to custom config: %v", err)
156196
}
157197
}
198+
return nil
199+
}
158200

201+
func listen(m *macaron.Macaron, handleRedirector bool) error {
159202
listenAddr := setting.HTTPAddr
160203
if setting.Protocol != setting.UnixSocket && setting.Protocol != setting.FCGIUnix {
161204
listenAddr = net.JoinHostPort(listenAddr, setting.HTTPPort)
@@ -166,37 +209,40 @@ func runWeb(ctx *cli.Context) error {
166209
log.Info("LFS server enabled")
167210
}
168211

169-
if setting.EnablePprof {
170-
go func() {
171-
log.Info("Starting pprof server on localhost:6060")
172-
log.Info("%v", http.ListenAndServe("localhost:6060", nil))
173-
}()
174-
}
175-
176212
var err error
177213
switch setting.Protocol {
178214
case setting.HTTP:
179-
NoHTTPRedirector()
215+
if handleRedirector {
216+
NoHTTPRedirector()
217+
}
180218
err = runHTTP("tcp", listenAddr, context2.ClearHandler(m))
181219
case setting.HTTPS:
182220
if setting.EnableLetsEncrypt {
183221
err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, context2.ClearHandler(m))
184222
break
185223
}
186-
if setting.RedirectOtherPort {
187-
go runHTTPRedirector()
188-
} else {
189-
NoHTTPRedirector()
224+
if handleRedirector {
225+
if setting.RedirectOtherPort {
226+
go runHTTPRedirector()
227+
} else {
228+
NoHTTPRedirector()
229+
}
190230
}
191231
err = runHTTPS("tcp", listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m))
192232
case setting.FCGI:
193-
NoHTTPRedirector()
233+
if handleRedirector {
234+
NoHTTPRedirector()
235+
}
194236
err = runFCGI("tcp", listenAddr, context2.ClearHandler(m))
195237
case setting.UnixSocket:
196-
NoHTTPRedirector()
238+
if handleRedirector {
239+
NoHTTPRedirector()
240+
}
197241
err = runHTTP("unix", listenAddr, context2.ClearHandler(m))
198242
case setting.FCGIUnix:
199-
NoHTTPRedirector()
243+
if handleRedirector {
244+
NoHTTPRedirector()
245+
}
200246
err = runFCGI("unix", listenAddr, context2.ClearHandler(m))
201247
default:
202248
log.Fatal("Invalid protocol: %s", setting.Protocol)
@@ -206,8 +252,5 @@ func runWeb(ctx *cli.Context) error {
206252
log.Critical("Failed to start server: %v", err)
207253
}
208254
log.Info("HTTP Listener: %s Closed", listenAddr)
209-
<-graceful.GetManager().Done()
210-
log.Info("PID: %d Gitea Web Finished", os.Getpid())
211-
log.Close()
212-
return nil
255+
return err
213256
}

‎cmd/web_graceful.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ func NoMainListener() {
3737
graceful.GetManager().InformCleanup()
3838
}
3939

40+
// NoInstallListener tells our cleanup routine that we will not be using a possibly provided listener
41+
// for our install HTTP/HTTPS service
42+
func NoInstallListener() {
43+
graceful.GetManager().InformCleanup()
44+
}
45+
4046
func runFCGI(network, listenAddr string, m http.Handler) error {
4147
// This needs to handle stdin as fcgi point
4248
fcgiServer := graceful.NewServer(network, listenAddr)

‎modules/context/auth.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,6 @@ type ToggleOptions struct {
2626
// Toggle returns toggle options as middleware
2727
func Toggle(options *ToggleOptions) macaron.Handler {
2828
return func(ctx *Context) {
29-
// Cannot view any page before installation.
30-
if !setting.InstallLock {
31-
ctx.Redirect(setting.AppSubURL + "/install")
32-
return
33-
}
34-
3529
isAPIPath := auth.IsAPIPath(ctx.Req.URL.Path)
3630

3731
// Check prohibit login users.

‎modules/graceful/manager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const (
3131
//
3232
// If you add an additional place you must increment this number
3333
// and add a function to call manager.InformCleanup if it's not going to be used
34-
const numberOfServersToCreate = 3
34+
const numberOfServersToCreate = 4
3535

3636
// Manager represents the graceful server manager interface
3737
var manager *Manager

‎modules/graceful/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func (srv *Server) Serve(serve ServeFunction) error {
162162
srv.setState(stateTerminate)
163163
GetManager().ServerDone()
164164
// use of closed means that the listeners are closed - i.e. we should be shutting down - return nil
165-
if err != nil && strings.Contains(err.Error(), "use of closed") {
165+
if err == nil || strings.Contains(err.Error(), "use of closed") || strings.Contains(err.Error(), "http: Server closed") {
166166
return nil
167167
}
168168
return err

‎routers/init.go

Lines changed: 71 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,46 @@ func InitLocales() {
117117
})
118118
}
119119

120+
// PreInstallInit preloads the configuration to check if we need to run install
121+
func PreInstallInit(ctx context.Context) bool {
122+
setting.NewContext()
123+
if !setting.InstallLock {
124+
log.Trace("AppPath: %s", setting.AppPath)
125+
log.Trace("AppWorkPath: %s", setting.AppWorkPath)
126+
log.Trace("Custom path: %s", setting.CustomPath)
127+
log.Trace("Log path: %s", setting.LogRootPath)
128+
log.Trace("Preparing to run install page")
129+
InitLocales()
130+
if setting.EnableSQLite3 {
131+
log.Info("SQLite3 Supported")
132+
}
133+
setting.InitDBConfig()
134+
svg.Init()
135+
}
136+
137+
return !setting.InstallLock
138+
}
139+
140+
// PostInstallInit rereads the settings and starts up the database
141+
func PostInstallInit(ctx context.Context) {
142+
setting.NewContext()
143+
setting.InitDBConfig()
144+
if setting.InstallLock {
145+
if err := initDBEngine(ctx); err == nil {
146+
log.Info("ORM engine initialization successful!")
147+
} else {
148+
log.Fatal("ORM engine initialization failed: %v", err)
149+
}
150+
svg.Init()
151+
}
152+
}
153+
120154
// GlobalInit is for global configuration reload-able.
121155
func GlobalInit(ctx context.Context) {
122156
setting.NewContext()
157+
if !setting.InstallLock {
158+
log.Fatal("Gitea is not installed")
159+
}
123160
if err := git.Init(ctx); err != nil {
124161
log.Fatal("Git module init failed: %v", err)
125162
}
@@ -134,59 +171,50 @@ func GlobalInit(ctx context.Context) {
134171

135172
NewServices()
136173

137-
if setting.InstallLock {
138-
highlight.NewContext()
139-
external.RegisterParsers()
140-
markup.Init()
141-
if err := initDBEngine(ctx); err == nil {
142-
log.Info("ORM engine initialization successful!")
143-
} else {
144-
log.Fatal("ORM engine initialization failed: %v", err)
145-
}
174+
highlight.NewContext()
175+
external.RegisterParsers()
176+
markup.Init()
177+
if err := initDBEngine(ctx); err == nil {
178+
log.Info("ORM engine initialization successful!")
179+
} else {
180+
log.Fatal("ORM engine initialization failed: %v", err)
181+
}
146182

147-
if err := models.InitOAuth2(); err != nil {
148-
log.Fatal("Failed to initialize OAuth2 support: %v", err)
149-
}
183+
if err := models.InitOAuth2(); err != nil {
184+
log.Fatal("Failed to initialize OAuth2 support: %v", err)
185+
}
150186

151-
models.NewRepoContext()
187+
models.NewRepoContext()
152188

153-
// Booting long running goroutines.
154-
cron.NewContext()
155-
issue_indexer.InitIssueIndexer(false)
156-
code_indexer.Init()
157-
if err := stats_indexer.Init(); err != nil {
158-
log.Fatal("Failed to initialize repository stats indexer queue: %v", err)
159-
}
160-
mirror_service.InitSyncMirrors()
161-
webhook.InitDeliverHooks()
162-
if err := pull_service.Init(); err != nil {
163-
log.Fatal("Failed to initialize test pull requests queue: %v", err)
164-
}
165-
if err := task.Init(); err != nil {
166-
log.Fatal("Failed to initialize task scheduler: %v", err)
167-
}
168-
eventsource.GetManager().Init()
189+
// Booting long running goroutines.
190+
cron.NewContext()
191+
issue_indexer.InitIssueIndexer(false)
192+
code_indexer.Init()
193+
if err := stats_indexer.Init(); err != nil {
194+
log.Fatal("Failed to initialize repository stats indexer queue: %v", err)
169195
}
196+
mirror_service.InitSyncMirrors()
197+
webhook.InitDeliverHooks()
198+
if err := pull_service.Init(); err != nil {
199+
log.Fatal("Failed to initialize test pull requests queue: %v", err)
200+
}
201+
if err := task.Init(); err != nil {
202+
log.Fatal("Failed to initialize task scheduler: %v", err)
203+
}
204+
eventsource.GetManager().Init()
205+
170206
if setting.EnableSQLite3 {
171207
log.Info("SQLite3 Supported")
172208
}
173209
checkRunMode()
174210

175-
// Now because Install will re-run GlobalInit once it has set InstallLock
176-
// we can't tell if the ssh port will remain unused until that's done.
177-
// However, see FIXME comment in install.go
178-
if setting.InstallLock {
179-
if setting.SSH.StartBuiltinServer {
180-
ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
181-
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)
182-
} else {
183-
ssh.Unused()
184-
}
185-
}
186-
187-
if setting.InstallLock {
188-
sso.Init()
211+
if setting.SSH.StartBuiltinServer {
212+
ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
213+
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)
214+
} else {
215+
ssh.Unused()
189216
}
217+
sso.Init()
190218

191219
svg.Init()
192220
}

‎routers/install.go

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
package routers
66

77
import (
8-
"errors"
8+
"net/http"
99
"os"
1010
"os/exec"
1111
"path/filepath"
@@ -27,13 +27,15 @@ import (
2727

2828
const (
2929
// tplInstall template for installation page
30-
tplInstall base.TplName = "install"
30+
tplInstall base.TplName = "install"
31+
tplPostInstall base.TplName = "post-install"
3132
)
3233

3334
// InstallInit prepare for rendering installation page
3435
func InstallInit(ctx *context.Context) {
3536
if setting.InstallLock {
36-
ctx.NotFound("Install", errors.New("Installation is prohibited"))
37+
ctx.Header().Add("Refresh", "1; url="+setting.AppURL+"user/login")
38+
ctx.HTML(200, tplPostInstall)
3739
return
3840
}
3941

@@ -357,7 +359,8 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
357359
return
358360
}
359361

360-
GlobalInit(graceful.GetManager().HammerContext())
362+
// Re-read settings
363+
PostInstallInit(ctx.Req.Context())
361364

362365
// Create admin account
363366
if len(form.AdminName) > 0 {
@@ -380,6 +383,11 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
380383
u, _ = models.GetUserByName(u.Name)
381384
}
382385

386+
days := 86400 * setting.LogInRememberDays
387+
ctx.SetCookie(setting.CookieUserName, u.Name, days, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
388+
ctx.SetSuperSecureCookie(base.EncodeMD5(u.Rands+u.Passwd),
389+
setting.CookieRememberName, u.Name, days, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
390+
383391
// Auto-login for admin
384392
if err = ctx.Session.Set("uid", u.ID); err != nil {
385393
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
@@ -397,12 +405,18 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
397405
}
398406

399407
log.Info("First-time run install finished!")
400-
// FIXME: This isn't really enough to completely take account of new configuration
401-
// We should really be restarting:
402-
// - On windows this is probably just a simple restart
403-
// - On linux we can't just use graceful.RestartProcess() everything that was passed in on LISTEN_FDS
404-
// (active or not) needs to be passed out and everything new passed out too.
405-
// This means we need to prevent the cleanup goroutine from running prior to the second GlobalInit
408+
406409
ctx.Flash.Success(ctx.Tr("install.install_success"))
407-
ctx.Redirect(form.AppURL + "user/login")
410+
411+
ctx.Header().Add("Refresh", "1; url="+setting.AppURL+"user/login")
412+
ctx.HTML(200, tplPostInstall)
413+
414+
// Now get the http.Server from this request and shut it down
415+
// NB: This is not our hammerable graceful shutdown this is http.Server.Shutdown
416+
srv := ctx.Req.Context().Value(http.ServerContextKey).(*http.Server)
417+
go func() {
418+
if err := srv.Shutdown(graceful.GetManager().HammerContext()); err != nil {
419+
log.Error("Unable to shutdown the install server! Error: %v", err)
420+
}
421+
}()
408422
}

‎routers/routes/routes.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,15 @@ func NewMacaron() *macaron.Macaron {
301301
return m
302302
}
303303

304+
// RegisterInstallRoute registers the install routes
305+
func RegisterInstallRoute(m *macaron.Macaron) {
306+
m.Combo("/", routers.InstallInit).Get(routers.Install).
307+
Post(binding.BindIgnErr(auth.InstallForm{}), routers.InstallPost)
308+
m.NotFound(func(ctx *context.Context) {
309+
ctx.Redirect(setting.AppURL, 302)
310+
})
311+
}
312+
304313
// RegisterRoutes routes routes to Macaron
305314
func RegisterRoutes(m *macaron.Macaron) {
306315
reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true})

‎templates/install.tmpl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<p>{{.i18n.Tr "install.docker_helper" "https://docs.gitea.io/en-us/install-with-docker/" | Safe}}</p>
1212

13-
<form class="ui form" action="{{AppSubUrl}}/install" method="post">
13+
<form class="ui form" action="{{AppSubUrl}}/" method="post">
1414
<!-- Database Settings -->
1515
<h4 class="ui dividing header">{{.i18n.Tr "install.db_title"}}</h4>
1616
<p>{{.i18n.Tr "install.requite_db_desc"}}</p>
@@ -307,4 +307,5 @@
307307
</div>
308308
</div>
309309
</div>
310+
<img style="display: none" src="{{StaticUrlPrefix}}/img/loading.png"/>
310311
{{template "base/footer" .}}

‎templates/post-install.tmpl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{{template "base/head" .}}
2+
<div class="install">
3+
<div class="ui container">
4+
<div class="ui grid">
5+
<div class="sixteen wide column content">
6+
<div class="home">
7+
<div class="ui stackable middle very relaxed page grid">
8+
<div id="repo_migrating" class="sixteen wide center aligned centered column">
9+
<div>
10+
<img src="{{StaticUrlPrefix}}/img/loading.png"/>
11+
</div>
12+
</div>
13+
</div>
14+
<div class="ui stackable middle very relaxed page grid">
15+
<div class="sixteen wide center aligned centered column">
16+
<p><a href="{{AppUrl}}user/login">{{AppUrl}}user/login</a></p>
17+
</div>
18+
</div>
19+
</div>
20+
</div>
21+
</div>
22+
</div>
23+
</div>
24+
{{template "base/footer" .}}

0 commit comments

Comments
 (0)
Please sign in to comment.