Nginx config files with suffixes for deleted/disabled/errors

This commit is contained in:
Jamie Curnow 2023-01-06 14:17:12 +10:00
parent 17a108f75f
commit 6efa4e2beb
5 changed files with 96 additions and 20 deletions

View File

@ -150,11 +150,6 @@ INSERT INTO `nginx_template` (
{{/each}}
# ------------------------------------------------------------
{{#if Host.IsDisabled}}
# This Proxy Host is disabled and will not generate functional config
{{/if}}
{{#unless Host.IsDisabled}}
server {
set $forward_scheme {{Host.ForwardScheme}} http; # todo
set $server ""{{Host.ForwardHost}}""; # todo
@ -270,7 +265,6 @@ server {
# Legacy Custom Configuration
include /data/nginx/custom/server_proxy[.]conf;
}
{{/unless}}
"
), (
strftime('%s', 'now'),
@ -303,8 +297,6 @@ server {
# Upstream {{Upstream.ID}}: {{Upstream.Name}}
# ------------------------------------------------------------
{{#unless Upstream.IsDeleted~}}
upstream npm_upstream_{{Upstream.ID}} {
{{#if Upstream.IPHash~}}
@ -339,8 +331,6 @@ upstream npm_upstream_{{Upstream.ID}} {
{{/unless}}
{{/each}}
}
{{~/unless~}}
"
);

View File

@ -152,6 +152,7 @@ func DeleteHost() func(http.ResponseWriter, *http.Request) {
h.ResultErrorJSON(w, r, http.StatusNotFound, "Not found", nil)
case nil:
h.ResultResponseJSON(w, r, http.StatusOK, item.Delete())
configureHost(item)
default:
h.ResultErrorJSON(w, r, http.StatusBadRequest, err.Error(), nil)
}

View File

@ -110,6 +110,7 @@ func DeleteUpstream() func(http.ResponseWriter, *http.Request) {
h.ResultErrorJSON(w, r, http.StatusNotFound, "Not found", nil)
case nil:
h.ResultResponseJSON(w, r, http.StatusOK, item.Delete())
configureUpstream(item)
default:
h.ResultErrorJSON(w, r, http.StatusBadRequest, err.Error(), nil)
}

View File

@ -2,6 +2,7 @@ package nginx
import (
"fmt"
"os"
"npm/internal/config"
"npm/internal/entity/certificate"
@ -11,7 +12,15 @@ import (
"npm/internal/status"
)
const (
DeletedSuffix = ".deleted"
DisabledSuffix = ".disabled"
ErrorSuffix = ".error"
)
// ConfigureHost will attempt to write nginx conf and reload nginx
// When a host is disabled or deleted, it will name the file with a suffix
// that won't be used by nginx.
func ConfigureHost(h host.Model) error {
// nolint: errcheck, gosec
h.Expand([]string{"certificate", "nginxtemplate", "upstream"})
@ -33,10 +42,16 @@ func ConfigureHost(h host.Model) error {
Upstream: h.Upstream,
}
filename := fmt.Sprintf("%s/host_%d.conf", data.ConfDir, h.ID)
removeHostFiles(h)
filename := getHostFilename(h, "")
if h.IsDeleted {
filename = getHostFilename(h, DeletedSuffix)
} else if h.IsDisabled {
filename = getHostFilename(h, DisabledSuffix)
}
// Write the config to disk
err := writeTemplate(filename, h.NginxTemplate.Template, data)
err := writeTemplate(filename, h.NginxTemplate.Template, data, "")
if err != nil {
// this configuration failed somehow
h.Status = status.StatusError
@ -45,12 +60,23 @@ func ConfigureHost(h host.Model) error {
return h.Save(true)
}
// nolint: errcheck, gosec
// Reload Nginx and check for errors
if output, err := reloadNginx(); err != nil {
// reloading nginx failed, likely due to this host having a problem
h.Status = status.StatusError
h.ErrorMessage = fmt.Sprintf("Nginx configuation error: %s - %s", err.Error(), output)
writeConfigFile(filename, fmt.Sprintf("# %s", h.ErrorMessage))
// Write the .error file, if this isn't a deleted or disabled host
// as the reload will only fail because of this host, if it's enabled
if !h.IsDeleted && !h.IsDisabled {
filename = getHostFilename(h, ErrorSuffix)
// Clear existing file(s) again
removeHostFiles(h)
// Write the template again, but with an error message at the end of the file
// nolint: errcheck, gosec
writeTemplate(filename, h.NginxTemplate.Template, data, h.ErrorMessage)
}
logger.Debug(h.ErrorMessage)
} else {
// All good
@ -75,10 +101,14 @@ func ConfigureUpstream(u upstream.Model) error {
Upstream: u,
}
filename := fmt.Sprintf("%s/upstream_%d.conf", data.ConfDir, u.ID)
removeUpstreamFiles(u)
filename := getUpstreamFilename(u, "")
if u.IsDeleted {
filename = getUpstreamFilename(u, DeletedSuffix)
}
// Write the config to disk
err := writeTemplate(filename, u.NginxTemplate.Template, data)
err := writeTemplate(filename, u.NginxTemplate.Template, data, "")
if err != nil {
// this configuration failed somehow
u.Status = status.StatusError
@ -92,7 +122,18 @@ func ConfigureUpstream(u upstream.Model) error {
// reloading nginx failed, likely due to this host having a problem
u.Status = status.StatusError
u.ErrorMessage = fmt.Sprintf("Nginx configuation error: %s - %s", err.Error(), output)
writeConfigFile(filename, fmt.Sprintf("# %s", u.ErrorMessage))
// Write the .error file, if this isn't a deleted upstream
// as the reload will only fail because of this upstream
if !u.IsDeleted {
filename = getUpstreamFilename(u, ErrorSuffix)
// Clear existing file(s) again
removeUpstreamFiles(u)
// Write the template again, but with an error message at the end of the file
// nolint: errcheck, gosec
writeTemplate(filename, u.NginxTemplate.Template, data, u.ErrorMessage)
}
logger.Debug(u.ErrorMessage)
} else {
// All good
@ -103,3 +144,39 @@ func ConfigureUpstream(u upstream.Model) error {
return u.Save(true)
}
func getHostFilename(h host.Model, append string) string {
confDir := fmt.Sprintf("%s/nginx/hosts", config.Configuration.DataFolder)
return fmt.Sprintf("%s/host_%d.conf%s", confDir, h.ID, append)
}
func getUpstreamFilename(u upstream.Model, append string) string {
confDir := fmt.Sprintf("%s/nginx/upstreams", config.Configuration.DataFolder)
return fmt.Sprintf("%s/upstream_%d.conf%s", confDir, u.ID, append)
}
func removeHostFiles(h host.Model) {
removeFiles([]string{
getHostFilename(h, ""),
getHostFilename(h, DeletedSuffix),
getHostFilename(h, DisabledSuffix),
getHostFilename(h, ErrorSuffix),
})
}
func removeUpstreamFiles(u upstream.Model) {
removeFiles([]string{
getUpstreamFilename(u, ""),
getUpstreamFilename(u, DeletedSuffix),
getUpstreamFilename(u, ErrorSuffix),
})
}
func removeFiles(files []string) {
for _, file := range files {
if _, err := os.Stat(file); err == nil {
// nolint: errcheck, gosec
os.Remove(file)
}
}
}

View File

@ -34,15 +34,22 @@ func renderTemplate(template string, data TemplateData) (string, error) {
return raymond.Render(template, data)
}
func writeTemplate(filename, template string, data TemplateData) error {
func writeTemplate(filename, template string, data TemplateData, errorInfo string) error {
output, err := renderTemplate(template, data)
if err != nil {
output = fmt.Sprintf("# Template Error: %s", err.Error())
errorInfo = err.Error()
}
output = util.CleanupWhitespace(output)
// Write some given error information to the end
if errorInfo != "" {
output = fmt.Sprintf("%s\n\n# =========================\n# ERROR:\n# %s\n# ========================\n", output, errorInfo)
}
// Write it. This will also write an error comment if generation failed
// nolint: gosec
writeErr := writeConfigFile(filename, util.CleanupWhitespace(output))
writeErr := writeConfigFile(filename, output)
if err != nil {
return err
}