mirror of
https://github.com/outbackdingo/labca.git
synced 2026-01-27 10:19:34 +00:00
Make initial setup phase more robust
This commit is contained in:
@@ -26,7 +26,7 @@ function wait_server() {
|
||||
fi
|
||||
set -e
|
||||
while [ $cnt -lt 40 ] && [ "$status" != "200" ]; do
|
||||
status=$(curl -o /dev/null -sSL --head --write-out '%{http_code}\n' $url &>>$LOGFILE)
|
||||
status=$(curl -o /dev/null -sSL --head --write-out '%{http_code}\n' $url 2>>$LOGFILE)
|
||||
let cnt=$cnt+1
|
||||
if [ "$status" != "200" ]; then
|
||||
sleep 5
|
||||
|
||||
91
gui/main.go
91
gui/main.go
@@ -218,7 +218,7 @@ func getSession(w http.ResponseWriter, r *http.Request) *sessions.Session {
|
||||
}
|
||||
|
||||
func errorHandler(w http.ResponseWriter, r *http.Request, err error, status int) {
|
||||
log.Printf("errorHandler: %v", err)
|
||||
log.Printf("errorHandler: err=%v\n", err)
|
||||
|
||||
w.WriteHeader(status)
|
||||
|
||||
@@ -374,7 +374,7 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
RequestBase: r.Header.Get("X-Request-Base"),
|
||||
}
|
||||
|
||||
if reg.Validate(false, false) == false {
|
||||
if !reg.Validate(false, false) {
|
||||
render(w, r, "login", map[string]interface{}{"User": reg, "IsLogin": true})
|
||||
return
|
||||
}
|
||||
@@ -618,7 +618,7 @@ func (cfg *EmailConfig) Validate() bool {
|
||||
cfg.Errors["EmailPwd"] = "Could not encrypt this password: " + err.Error()
|
||||
}
|
||||
|
||||
if cfg.DoEmail == false {
|
||||
if !cfg.DoEmail {
|
||||
return len(cfg.Errors) == 0
|
||||
}
|
||||
|
||||
@@ -979,7 +979,7 @@ func _managePost(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
if !actionKnown {
|
||||
errorHandler(w, r, fmt.Errorf("Unknown manage action '%s'", action), http.StatusBadRequest)
|
||||
errorHandler(w, r, fmt.Errorf("unknown manage action '%s'", action), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1198,7 +1198,7 @@ func logsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
wsurl = ""
|
||||
data = getLog(w, r, logType)
|
||||
default:
|
||||
errorHandler(w, r, fmt.Errorf("Unknown log type '%s'", logType), http.StatusBadRequest)
|
||||
errorHandler(w, r, fmt.Errorf("unknown log type '%s'", logType), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1267,7 +1267,7 @@ func showLog(ws *websocket.Conn, logType string) {
|
||||
scanner := bufio.NewScanner(conn)
|
||||
for scanner.Scan() {
|
||||
msg := scanner.Text()
|
||||
if logType != "audit" || strings.Index(msg, "[AUDIT]") > -1 {
|
||||
if logType != "audit" || strings.Contains(msg, "[AUDIT]") {
|
||||
ws.SetWriteDeadline(time.Now().Add(writeWait))
|
||||
if err := ws.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil {
|
||||
// Probably "websocket: close sent"
|
||||
@@ -1279,8 +1279,6 @@ func showLog(ws *websocket.Conn, logType string) {
|
||||
wsErrorHandler(err)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func reader(ws *websocket.Conn) {
|
||||
@@ -1334,7 +1332,7 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
case "labca":
|
||||
case "web":
|
||||
default:
|
||||
errorHandler(w, r, fmt.Errorf("Unknown log type '%s'", logType), http.StatusBadRequest)
|
||||
errorHandler(w, r, fmt.Errorf("unknown log type '%s'", logType), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1432,7 +1430,7 @@ func _certCreate(w http.ResponseWriter, r *http.Request, certBase string, isRoot
|
||||
ci.Certificate = r.Form.Get("certificate")
|
||||
ci.RequestBase = r.Header.Get("X-Request-Base")
|
||||
|
||||
if ci.Validate() == false {
|
||||
if !ci.Validate() {
|
||||
render(w, r, "cert:manage", map[string]interface{}{"CertificateInfo": ci, "Progress": _progress(certBase), "HelpText": _helptext(certBase)})
|
||||
return false
|
||||
}
|
||||
@@ -1698,7 +1696,7 @@ func _setupAdminUser(w http.ResponseWriter, r *http.Request) bool {
|
||||
RequestBase: r.Header.Get("X-Request-Base"),
|
||||
}
|
||||
|
||||
if reg.Validate(true, false) == false {
|
||||
if !reg.Validate(true, false) {
|
||||
render(w, r, "register:manage", map[string]interface{}{"User": reg, "IsLogin": true, "Progress": _progress("register"), "HelpText": _helptext("register")})
|
||||
return false
|
||||
}
|
||||
@@ -1761,7 +1759,7 @@ func _setupBaseConfig(w http.ResponseWriter, r *http.Request) bool {
|
||||
RequestBase: r.Header.Get("X-Request-Base"),
|
||||
}
|
||||
|
||||
if cfg.Validate(false) == false {
|
||||
if !cfg.Validate(false) {
|
||||
render(w, r, "setup:manage", map[string]interface{}{"SetupConfig": cfg, "Progress": _progress("setup"), "HelpText": _helptext("setup")})
|
||||
return false
|
||||
}
|
||||
@@ -1886,40 +1884,60 @@ func finalHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Don't let the retry mechanism trigger a certificate request and restart!
|
||||
if r.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||
render(w, r, "index", map[string]interface{}{"Message": "Retry OK"})
|
||||
} else {
|
||||
t := viper.GetTime("config.cert_requested")
|
||||
if !t.IsZero() && t.After(time.Now().Add(-5*time.Minute)) {
|
||||
t := viper.GetTime("config.cert_requested")
|
||||
if !t.IsZero() && t.After(time.Now().Add(-5*time.Minute)) {
|
||||
// Too soon
|
||||
if r.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if viper.GetBool("config.error") {
|
||||
viper.Set("config.cert_requested", nil)
|
||||
viper.WriteConfig()
|
||||
}
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{"complete": viper.GetBool("config.complete"), "error": viper.GetBool("config.error")})
|
||||
} else {
|
||||
render(w, r, "polling:manage", map[string]interface{}{"Progress": _progress("polling"), "HelpText": _helptext("polling")})
|
||||
return
|
||||
}
|
||||
viper.Set("config.cert_requested", time.Now())
|
||||
return
|
||||
}
|
||||
|
||||
viper.Set("config.cert_requested", time.Now())
|
||||
if viper.GetBool("config.error") {
|
||||
viper.Set("config.error", false)
|
||||
}
|
||||
viper.WriteConfig()
|
||||
// 9. Setup our own web certificate
|
||||
if !_hostCommand(w, r, "acme-request") {
|
||||
viper.Set("config.error", true)
|
||||
viper.WriteConfig()
|
||||
// 9. Setup our own web certificate
|
||||
if !_hostCommand(w, r, "acme-request") {
|
||||
http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/logs/cert", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/logs/cert", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
// 10. remove the temporary bit from nginx config
|
||||
if !_hostCommand(w, r, "nginx-remove-redirect") {
|
||||
return
|
||||
}
|
||||
// 10. remove the temporary bit from nginx config
|
||||
if !_hostCommand(w, r, "nginx-remove-redirect") {
|
||||
return
|
||||
}
|
||||
|
||||
// 11. reload nginx
|
||||
if !_hostCommand(w, r, "nginx-reload") {
|
||||
return
|
||||
}
|
||||
// 11. reload nginx
|
||||
if !_hostCommand(w, r, "nginx-reload") {
|
||||
return
|
||||
}
|
||||
|
||||
viper.Set("config.complete", true)
|
||||
viper.WriteConfig()
|
||||
viper.Set("config.complete", true)
|
||||
viper.WriteConfig()
|
||||
|
||||
if r.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{"complete": viper.GetBool("config.complete")})
|
||||
} else {
|
||||
render(w, r, "final:manage", map[string]interface{}{"RequestBase": r.Header.Get("X-Request-Base"), "Progress": _progress("final"), "HelpText": _helptext("final")})
|
||||
}
|
||||
}
|
||||
|
||||
func showErrorHandler(w http.ResponseWriter, r *http.Request) {
|
||||
errorHandler(w, r, nil, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// RangeStructer takes the first argument, which must be a struct, and
|
||||
// returns the value of each field in a slice. It will return nil
|
||||
// if there are no arguments or first argument is not a struct
|
||||
@@ -2105,7 +2123,7 @@ func certificateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func certRevokeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !viper.GetBool("config.complete") {
|
||||
errorHandler(w, r, errors.New("Method not allowed at this point"), http.StatusMethodNotAllowed)
|
||||
errorHandler(w, r, errors.New("method not allowed at this point"), http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2443,6 +2461,7 @@ func main() {
|
||||
r.HandleFunc("/about", aboutHandler).Methods("GET")
|
||||
r.HandleFunc("/manage", manageHandler).Methods("GET", "POST")
|
||||
r.HandleFunc("/final", finalHandler).Methods("GET")
|
||||
r.HandleFunc("/error", showErrorHandler).Methods("GET")
|
||||
r.HandleFunc("/login", loginHandler).Methods("GET", "POST")
|
||||
r.HandleFunc("/logout", logoutHandler).Methods("GET")
|
||||
r.HandleFunc("/logs/{type}", logsHandler).Methods("GET")
|
||||
|
||||
1
www/css/bootstrap.min.css.map
Normal file
1
www/css/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
@@ -182,7 +182,6 @@ $(function() {
|
||||
positionFooter();
|
||||
});
|
||||
|
||||
|
||||
$("#restart-button").click(function(evt) {
|
||||
$("#pre-restart-1").hide();
|
||||
$("#pre-restart-2").hide();
|
||||
@@ -198,14 +197,22 @@ $(function() {
|
||||
}
|
||||
}
|
||||
var secret = "";
|
||||
var nextPath = "";
|
||||
if (args[0] == "restart") {
|
||||
secret = args[1];
|
||||
nextPath = "/restart";
|
||||
}
|
||||
|
||||
var pollTimer;
|
||||
|
||||
var baseUrl = window.location.href.substr(0, window.location.href.indexOf("?")).replace("/wait", "");
|
||||
$.ajax(baseUrl + "/restart", {
|
||||
var baseUrl = window.location.href;
|
||||
if (baseUrl.indexOf("?") > 0) {
|
||||
baseUrl = baseUrl.substr(0, baseUrl.indexOf("?"));
|
||||
}
|
||||
if (baseUrl.endsWith("/wait")) {
|
||||
baseUrl = baseUrl.substr(0, baseUrl.length-5);
|
||||
}
|
||||
$.ajax(baseUrl + nextPath, {
|
||||
data: {
|
||||
token: secret,
|
||||
},
|
||||
@@ -216,33 +223,35 @@ $(function() {
|
||||
window.location.href = baseUrl + "/setup";
|
||||
})
|
||||
.fail(function(xhr, status, err) {
|
||||
if (err === "timeout" || err === "Bad Gateway") {
|
||||
// Assume that the restart was initiated... Wait for server to be available again.
|
||||
var ctr = 0;
|
||||
pollTimer = setInterval(pollServer, 3000);
|
||||
pollServer();
|
||||
nextPath = "";
|
||||
// Assume that the restart was initiated... Wait for server to be available again.
|
||||
var ctr = 0;
|
||||
pollTimer = setInterval(pollServer, 3000);
|
||||
|
||||
function pollServer() {
|
||||
if (ctr > 59) {
|
||||
function pollServer() {
|
||||
if (ctr > 59) {
|
||||
clearInterval(pollTimer);
|
||||
$("img#restart-spinner").parent().text("timeout").addClass("error");
|
||||
} else if (ctr < 10) {
|
||||
// No need to try immediately, the server is restarting
|
||||
ctr++;
|
||||
} else {
|
||||
$.ajax(baseUrl + nextPath, {
|
||||
timeout: 2500
|
||||
})
|
||||
.done(function(data) {
|
||||
clearInterval(pollTimer);
|
||||
$("img#restart-spinner").parent().text("timeout").addClass("error");
|
||||
} else {
|
||||
$.ajax(baseUrl + "/setup", {
|
||||
timeout: 2500
|
||||
})
|
||||
.done(function(data) {
|
||||
window.location.href = baseUrl;
|
||||
})
|
||||
.fail(function(xhr, status, err) {
|
||||
ctr++;
|
||||
if ((typeof err === 'undefined' || err === "") && status === "error") {
|
||||
// Probably because the certificate has changed
|
||||
clearInterval(pollTimer);
|
||||
window.location.href = baseUrl + "/setup";
|
||||
})
|
||||
.fail(function(xhr, status, err) {
|
||||
ctr++;
|
||||
});
|
||||
}
|
||||
window.location.href = baseUrl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
clearInterval(pollTimer);
|
||||
$("img#restart-spinner").parent().text(err).addClass("error");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -252,23 +261,37 @@ $(function() {
|
||||
if ( $("img#wrapup-spinner").length ) {
|
||||
var targetUrl = window.location.href.replace("/setup", "/final");
|
||||
var ctr = 0;
|
||||
var pollTimer = setInterval(pollServer, 3000);
|
||||
pollServer();
|
||||
var pollTimer = setInterval(pollServer, 5000);
|
||||
|
||||
function pollServer() {
|
||||
if (ctr > 20) {
|
||||
if (ctr > 60) {
|
||||
clearInterval(pollTimer);
|
||||
$("img#wrapup-spinner").parent().text("timeout").addClass("error");
|
||||
} else if (ctr < 5) {
|
||||
// No need to try immediately, the server won't be ready this quick
|
||||
ctr++;
|
||||
} else {
|
||||
$.ajax(targetUrl, {
|
||||
timeout: 2500
|
||||
timeout: 4500
|
||||
})
|
||||
.done(function(data) {
|
||||
clearInterval(pollTimer);
|
||||
window.location.href = targetUrl;
|
||||
if (data.error) {
|
||||
clearInterval(pollTimer);
|
||||
targetUrl = targetUrl.replace("/final", "/error");
|
||||
window.location.href = targetUrl;
|
||||
} else if (data.complete) {
|
||||
clearInterval(pollTimer);
|
||||
targetUrl = targetUrl.replace("/final", "");
|
||||
window.location.href = targetUrl;
|
||||
}
|
||||
})
|
||||
.fail(function(xhr, status, err) {
|
||||
ctr++;
|
||||
if ((typeof err === 'undefined' || err === "") && status === "error") {
|
||||
// Probably because the certificate has changed
|
||||
clearInterval(pollTimer);
|
||||
window.location.href = targetUrl;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user