From 1a9730bac96b251b9372b74a576ef91e385f0671 Mon Sep 17 00:00:00 2001 From: Carlos Lapao Date: Mon, 18 Nov 2024 08:58:58 +0000 Subject: [PATCH] Fixing the issues with the reverse proxy (#242) - Fixed an issue where the reverse proxy would fail to initialize due to prot conflict and any attempt to restart would crash - fixed an issue where we allowed routes to be created even if the reverse proxy was disabled - fixed an issue where if the config changes in memory we would not save those changes - added the ability to choose the port and host trough configuration or env variables --- src/config/main.go | 38 ++-- src/constants/main.go | 2 + src/controllers/reverse_proxy.go | 351 +++++++++++++++++------------ src/data/models/reverse_proxy.go | 12 +- src/data/reverse_proxy.go | 33 +++ src/mappers/reverse_proxy.go | 9 +- src/reverse_proxy/main.go | 83 ++++++- src/reverse_proxy/models/config.go | 8 + 8 files changed, 358 insertions(+), 178 deletions(-) create mode 100644 src/reverse_proxy/models/config.go diff --git a/src/config/main.go b/src/config/main.go index ce7ef36..32c395d 100644 --- a/src/config/main.go +++ b/src/config/main.go @@ -506,29 +506,25 @@ func (c *Config) IsReverseProxyEnabled() bool { return true } -func (c *Config) GetReverseProxyConfig() *ReverseProxyConfig { - if c.config.ReverseProxy == nil { - c.config.ReverseProxy = &ReverseProxyConfig{ - Host: "localhost", - Port: "8080", - } - if c.TlsEnabled() { - c.config.ReverseProxy.Ssl = &ReverseProxyConfigSsl{ - Enabled: true, - Cert: c.TlsCertificate(), - Key: c.TlsPrivateKey(), - } - } - if c.IsCorsEnabled() { - c.config.ReverseProxy.Cors = &ReverseProxyConfigCors{ - Enabled: true, - AllowedOrigins: []string{"*"}, - AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "PATCH", "CONNECT", "TRACE"}, - AllowedHeaders: []string{"*"}, - } - } +func (c *Config) ReverseProxyHost() string { + host := c.GetKey(constants.REVERSE_PROXY_HOST_ENV_VAR) + if host == "" { + host = constants.DEFAULT_REVERSE_PROXY_HOST } + return host +} + +func (c *Config) ReverseProxyPort() string { + port := c.GetKey(constants.REVERSE_PROXY_PORT_ENV_VAR) + if port == "" { + port = constants.DEFAULT_REVERSE_PROXY_PORT + } + + return port +} + +func (c *Config) GetReverseProxyConfig() *ReverseProxyConfig { return c.config.ReverseProxy } diff --git a/src/constants/main.go b/src/constants/main.go index 39ec1f4..c3125f6 100644 --- a/src/constants/main.go +++ b/src/constants/main.go @@ -38,6 +38,8 @@ const ( DEFAULT_SYSTEM_RESERVED_CPU = 1 DEFAULT_SYSTEM_RESERVED_MEMORY = 2048 DEFAULT_SYSTEM_RESERVED_DISK = 20000 + DEFAULT_REVERSE_PROXY_PORT = "5080" + DEFAULT_REVERSE_PROXY_HOST = "0.0.0.0" API_MODE = "api" CLI_MODE = "cli" diff --git a/src/controllers/reverse_proxy.go b/src/controllers/reverse_proxy.go index d8445c8..1aa926f 100644 --- a/src/controllers/reverse_proxy.go +++ b/src/controllers/reverse_proxy.go @@ -27,6 +27,7 @@ func registerReverseProxyHandlers(ctx basecontext.ApiContext, version string) { WithRequiredClaim(constants.CONFIGURE_REVERSE_PROXY_CLAIM). WithHandler(GetReverseProxyConfigHandler()). Register() + restapi.NewController(). WithMethod(restapi.GET). WithVersion(version).WithPath("/reverse-proxy/hosts"). @@ -95,55 +96,45 @@ func registerReverseProxyHandlers(ctx basecontext.ApiContext, version string) { Register() } -// @Summary Gets reverse proxy configuration -// @Description This endpoint returns the reverse proxy configuration -// @Tags ReverseProxy -// @Produce json -// @Success 200 {object} []models.ReverseProxy -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy [get] +// @Summary Gets reverse proxy configuration +// @Description This endpoint returns the reverse proxy configuration +// @Tags ReverseProxy +// @Produce json +// @Success 200 {object} []models.ReverseProxy +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy [get] func GetReverseProxyConfigHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() ctx := GetBaseContext(r) - cfg := config.Get() - defer Recover(ctx, r, w) - dbService, err := serviceprovider.GetDatabaseService(ctx) - if err != nil { - ReturnApiError(ctx, w, models.NewFromErrorWithCode(err, http.StatusInternalServerError)) - return - } - config, err := dbService.GetReverseProxyConfig(ctx) - if err != nil { - ReturnApiError(ctx, w, models.NewFromError(err)) - return - } + defer Recover(ctx, r, w) - result := mappers.DtoReverseProxyToApi(*config) - if cfg.IsReverseProxyEnabled() { - result.Enabled = true + config := reverse_proxy.GetConfig() + if !config.Enabled { + config.Host = "" + config.Port = "" } w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(result) + _ = json.NewEncoder(w).Encode(config) ctx.LogInfof("Reverse Proxy Config returned successfully") } } -// @Summary Gets all the reverse proxy hosts -// @Description This endpoint returns all the reverse proxy hosts -// @Tags ReverseProxy -// @Produce json -// @Success 200 {object} []models.ReverseProxyHost -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy/hosts [get] +// @Summary Gets all the reverse proxy hosts +// @Description This endpoint returns all the reverse proxy hosts +// @Tags ReverseProxy +// @Produce json +// @Success 200 {object} []models.ReverseProxyHost +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy/hosts [get] func GetReverseProxyHostsHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -155,6 +146,12 @@ func GetReverseProxyHostsHandler() restapi.ControllerHandler { return } + cfg := config.Get() + if !cfg.IsReverseProxyEnabled() { + ReturnApiError(ctx, w, models.NewFromErrorWithCode(errors.New("reverse proxy is disabled"), http.StatusBadRequest)) + return + } + dtoRpHosts, err := dbService.GetReverseProxyHosts(ctx, GetFilterHeader(r)) if err != nil { ReturnApiError(ctx, w, models.NewFromError(err)) @@ -178,17 +175,17 @@ func GetReverseProxyHostsHandler() restapi.ControllerHandler { } } -// @Summary Gets all the reverse proxy host -// @Description This endpoint returns a reverse proxy host -// @Tags ReverseProxy -// @Produce json -// @Param id path string true "Reverse Proxy Host ID" -// @Success 200 {object} models.ReverseProxyHost -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy/hosts/{id} [get] +// @Summary Gets all the reverse proxy host +// @Description This endpoint returns a reverse proxy host +// @Tags ReverseProxy +// @Produce json +// @Param id path string true "Reverse Proxy Host ID" +// @Success 200 {object} models.ReverseProxyHost +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy/hosts/{id} [get] func GetReverseProxyHostHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -200,6 +197,12 @@ func GetReverseProxyHostHandler() restapi.ControllerHandler { return } + cfg := config.Get() + if !cfg.IsReverseProxyEnabled() { + ReturnApiError(ctx, w, models.NewFromErrorWithCode(errors.New("reverse proxy is disabled"), http.StatusBadRequest)) + return + } + vars := mux.Vars(r) id := vars["id"] @@ -217,17 +220,17 @@ func GetReverseProxyHostHandler() restapi.ControllerHandler { } } -// @Summary Creates a reverse proxy host -// @Description This endpoint creates a reverse proxy host -// @Tags ReverseProxy -// @Produce json -// @Param reverse_proxy_create_request body models.ReverseProxyHostCreateRequest true "Reverse Host Request" -// @Success 200 {object} models.ReverseProxyHost -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy/hosts [post] +// @Summary Creates a reverse proxy host +// @Description This endpoint creates a reverse proxy host +// @Tags ReverseProxy +// @Produce json +// @Param reverse_proxy_create_request body models.ReverseProxyHostCreateRequest true "Reverse Host Request" +// @Success 200 {object} models.ReverseProxyHost +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy/hosts [post] func CreateReverseProxyHostHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -249,6 +252,12 @@ func CreateReverseProxyHostHandler() restapi.ControllerHandler { return } + cfg := config.Get() + if !cfg.IsReverseProxyEnabled() { + ReturnApiError(ctx, w, models.NewFromErrorWithCode(errors.New("reverse proxy is disabled"), http.StatusBadRequest)) + return + } + dbService, err := serviceprovider.GetDatabaseService(ctx) if err != nil { ReturnApiError(ctx, w, models.NewFromErrorWithCode(err, http.StatusInternalServerError)) @@ -277,17 +286,17 @@ func CreateReverseProxyHostHandler() restapi.ControllerHandler { } } -// @Summary Updates a reverse proxy host -// @Description This endpoint creates a reverse proxy host -// @Tags ReverseProxy -// @Produce json -// @Param reverse_proxy_update_request body models.ReverseProxyHostUpdateRequest true "Reverse Host Request" -// @Success 200 {object} models.ReverseProxyHost -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy/hosts/{id} [put] +// @Summary Updates a reverse proxy host +// @Description This endpoint creates a reverse proxy host +// @Tags ReverseProxy +// @Produce json +// @Param reverse_proxy_update_request body models.ReverseProxyHostUpdateRequest true "Reverse Host Request" +// @Success 200 {object} models.ReverseProxyHost +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy/hosts/{id} [put] func UpdateReverseProxyHostHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -308,6 +317,11 @@ func UpdateReverseProxyHostHandler() restapi.ControllerHandler { }) return } + cfg := config.Get() + if !cfg.IsReverseProxyEnabled() { + ReturnApiError(ctx, w, models.NewFromErrorWithCode(errors.New("reverse proxy is disabled"), http.StatusBadRequest)) + return + } vars := mux.Vars(r) id := vars["id"] @@ -362,17 +376,17 @@ func UpdateReverseProxyHostHandler() restapi.ControllerHandler { } } -// @Summary Delete a a reverse proxy host -// @Description This endpoint Deletes a reverse proxy host -// @Tags ReverseProxy -// @Produce json -// @Param id path string true "Reverse Proxy Host ID" -// @Success 202 -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy/hosts/{id} [delete] +// @Summary Delete a a reverse proxy host +// @Description This endpoint Deletes a reverse proxy host +// @Tags ReverseProxy +// @Produce json +// @Param id path string true "Reverse Proxy Host ID" +// @Success 202 +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy/hosts/{id} [delete] func DeleteReverseProxyHostHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -383,6 +397,11 @@ func DeleteReverseProxyHostHandler() restapi.ControllerHandler { ReturnApiError(ctx, w, models.NewFromErrorWithCode(err, http.StatusInternalServerError)) return } + cfg := config.Get() + if !cfg.IsReverseProxyEnabled() { + ReturnApiError(ctx, w, models.NewFromErrorWithCode(errors.New("reverse proxy is disabled"), http.StatusBadRequest)) + return + } vars := mux.Vars(r) id := vars["id"] @@ -404,17 +423,17 @@ func DeleteReverseProxyHostHandler() restapi.ControllerHandler { } } -// @Summary Creates or updates a reverse proxy host HTTP route -// @Description This endpoint creates or updates a reverse proxy host HTTP route -// @Tags ReverseProxy -// @Produce json -// @Param reverse_proxy_http_route_request body models.ReverseProxyHostHttpRouteCreateRequest true "Reverse Host Request" -// @Success 200 {object} models.ReverseProxyHost -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy/hosts/{id}/http_route [post] +// @Summary Creates or updates a reverse proxy host HTTP route +// @Description This endpoint creates or updates a reverse proxy host HTTP route +// @Tags ReverseProxy +// @Produce json +// @Param reverse_proxy_http_route_request body models.ReverseProxyHostHttpRouteCreateRequest true "Reverse Host Request" +// @Success 200 {object} models.ReverseProxyHost +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy/hosts/{id}/http_route [post] func UpsertReverseProxyHostHttpRouteHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -435,6 +454,11 @@ func UpsertReverseProxyHostHttpRouteHandler() restapi.ControllerHandler { }) return } + cfg := config.Get() + if !cfg.IsReverseProxyEnabled() { + ReturnApiError(ctx, w, models.NewFromErrorWithCode(errors.New("reverse proxy is disabled"), http.StatusBadRequest)) + return + } vars := mux.Vars(r) id := vars["id"] @@ -508,18 +532,18 @@ func UpsertReverseProxyHostHttpRouteHandler() restapi.ControllerHandler { } } -// @Summary Delete a a reverse proxy host HTTP route -// @Description This endpoint Deletes a reverse proxy host HTTP route -// @Tags ReverseProxy -// @Produce json -// @Param id path string true "Reverse Proxy Host ID" -// @Param http_route_id path string true "Reverse Proxy Host HTTP Route ID" -// @Success 202 -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy/hosts/{id}/http_routes/{http_route_id} [delete] +// @Summary Delete a a reverse proxy host HTTP route +// @Description This endpoint Deletes a reverse proxy host HTTP route +// @Tags ReverseProxy +// @Produce json +// @Param id path string true "Reverse Proxy Host ID" +// @Param http_route_id path string true "Reverse Proxy Host HTTP Route ID" +// @Success 202 +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy/hosts/{id}/http_routes/{http_route_id} [delete] func DeleteReverseProxyHostHttpRoutesHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -530,6 +554,11 @@ func DeleteReverseProxyHostHttpRoutesHandler() restapi.ControllerHandler { ReturnApiError(ctx, w, models.NewFromErrorWithCode(err, http.StatusInternalServerError)) return } + cfg := config.Get() + if !cfg.IsReverseProxyEnabled() { + ReturnApiError(ctx, w, models.NewFromErrorWithCode(errors.New("reverse proxy is disabled"), http.StatusBadRequest)) + return + } vars := mux.Vars(r) id := vars["id"] @@ -552,17 +581,17 @@ func DeleteReverseProxyHostHttpRoutesHandler() restapi.ControllerHandler { } } -// @Summary Updates a reverse proxy host TCP route -// @Description This endpoint updates a reverse proxy host TCP route -// @Tags ReverseProxy -// @Produce json -// @Param reverse_proxy_tcp_route_request body models.ReverseProxyHostTcpRouteCreateRequest true "Reverse Host Request" -// @Success 200 {object} models.ReverseProxyHost -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy/hosts/{id}/http_routes [post] +// @Summary Updates a reverse proxy host TCP route +// @Description This endpoint updates a reverse proxy host TCP route +// @Tags ReverseProxy +// @Produce json +// @Param reverse_proxy_tcp_route_request body models.ReverseProxyHostTcpRouteCreateRequest true "Reverse Host Request" +// @Success 200 {object} models.ReverseProxyHost +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy/hosts/{id}/http_routes [post] func UpdateReverseProxyHostTcpRouteHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -583,6 +612,11 @@ func UpdateReverseProxyHostTcpRouteHandler() restapi.ControllerHandler { }) return } + cfg := config.Get() + if !cfg.IsReverseProxyEnabled() { + ReturnApiError(ctx, w, models.NewFromErrorWithCode(errors.New("reverse proxy is disabled"), http.StatusBadRequest)) + return + } vars := mux.Vars(r) id := vars["id"] @@ -641,22 +675,28 @@ func UpdateReverseProxyHostTcpRouteHandler() restapi.ControllerHandler { } } -// @Summary Restarts the reverse proxy -// @Description This endpoint will restart the reverse proxy -// @Tags ReverseProxy -// @Produce json -// @Success 202 -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy/restart [put] +// @Summary Restarts the reverse proxy +// @Description This endpoint will restart the reverse proxy +// @Tags ReverseProxy +// @Produce json +// @Success 202 +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy/restart [put] func RestartReverseProxyHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() ctx := GetBaseContext(r) defer Recover(ctx, r, w) + rpConfig := reverse_proxy.GetConfig() + if !rpConfig.Enabled { + ReturnApiError(ctx, w, models.NewFromErrorWithCode(errors.New("reverse proxy is disabled"), http.StatusBadRequest)) + return + } + rps := reverse_proxy.Get(ctx) if err := rps.Restart(); err != nil { ReturnApiError(ctx, w, models.NewFromError(err)) @@ -668,16 +708,16 @@ func RestartReverseProxyHandler() restapi.ControllerHandler { } } -// @Summary Enable the reverse proxy -// @Description This endpoint will enable the reverse proxy -// @Tags ReverseProxy -// @Produce json -// @Success 202 -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy/enable [put] +// @Summary Enable the reverse proxy +// @Description This endpoint will enable the reverse proxy +// @Tags ReverseProxy +// @Produce json +// @Success 202 +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy/enable [put] func EnableReverseProxyHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -698,6 +738,18 @@ func EnableReverseProxyHandler() restapi.ControllerHandler { } }() } + + dbService, err := serviceprovider.GetDatabaseService(ctx) + if err != nil { + ReturnApiError(ctx, w, models.NewFromErrorWithCode(err, http.StatusInternalServerError)) + return + } + + if _, err := dbService.EnableProxyConfig(ctx); err != nil { + ReturnApiError(ctx, w, models.NewFromError(err)) + return + } + cfg.EnableReverseProxy(true) cfg.Save() @@ -706,16 +758,16 @@ func EnableReverseProxyHandler() restapi.ControllerHandler { } } -// @Summary Disable the reverse proxy -// @Description This endpoint will disable the reverse proxy -// @Tags ReverseProxy -// @Produce json -// @Success 202 -// @Failure 400 {object} models.ApiErrorResponse -// @Failure 401 {object} models.OAuthErrorResponse -// @Security ApiKeyAuth -// @Security BearerAuth -// @Router /v1/reverse-proxy/disable [put] +// @Summary Disable the reverse proxy +// @Description This endpoint will disable the reverse proxy +// @Tags ReverseProxy +// @Produce json +// @Success 202 +// @Failure 400 {object} models.ApiErrorResponse +// @Failure 401 {object} models.OAuthErrorResponse +// @Security ApiKeyAuth +// @Security BearerAuth +// @Router /v1/reverse-proxy/disable [put] func DisableReverseProxyHandler() restapi.ControllerHandler { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -728,6 +780,17 @@ func DisableReverseProxyHandler() restapi.ControllerHandler { _ = rps.Stop() } + dbService, err := serviceprovider.GetDatabaseService(ctx) + if err != nil { + ReturnApiError(ctx, w, models.NewFromErrorWithCode(err, http.StatusInternalServerError)) + return + } + + if _, err := dbService.DisableProxyConfig(ctx); err != nil { + ReturnApiError(ctx, w, models.NewFromError(err)) + return + } + cfg.EnableReverseProxy(false) cfg.Save() diff --git a/src/data/models/reverse_proxy.go b/src/data/models/reverse_proxy.go index e8be2ed..058b166 100644 --- a/src/data/models/reverse_proxy.go +++ b/src/data/models/reverse_proxy.go @@ -6,16 +6,20 @@ import ( ) type ReverseProxy struct { - ID string `json:"id"` - HostID string `json:"host_id,omitempty"` - Host string `json:"host"` - Port string `json:"port"` + ID string `json:"id"` + HostID string `json:"host_id,omitempty"` + Enabled bool `json:"enabled"` + Host string `json:"host"` + Port string `json:"port"` } func (o *ReverseProxy) Diff(source ReverseProxy) bool { if o == nil { return true } + if o.Enabled != source.Enabled { + return true + } if o.Host != source.Host { return true } diff --git a/src/data/reverse_proxy.go b/src/data/reverse_proxy.go index 15bf564..db4c7f9 100644 --- a/src/data/reverse_proxy.go +++ b/src/data/reverse_proxy.go @@ -25,6 +25,34 @@ func (j *JsonDatabase) GetReverseProxyConfig(ctx basecontext.ApiContext) (*model return j.data.ReverseProxy, nil } +func (j *JsonDatabase) EnableProxyConfig(ctx basecontext.ApiContext) (*models.ReverseProxy, error) { + if !j.IsConnected() { + return nil, ErrDatabaseNotConnected + } + + if j.data.ReverseProxy == nil { + return nil, errors.NewWithCode("reverse proxy config not found", 404) + } + + j.data.ReverseProxy.Enabled = true + + return j.data.ReverseProxy, nil +} + +func (j *JsonDatabase) DisableProxyConfig(ctx basecontext.ApiContext) (*models.ReverseProxy, error) { + if !j.IsConnected() { + return nil, ErrDatabaseNotConnected + } + + if j.data.ReverseProxy == nil { + return nil, errors.NewWithCode("reverse proxy config not found", 404) + } + + j.data.ReverseProxy.Enabled = false + + return j.data.ReverseProxy, nil +} + func (j *JsonDatabase) UpdateReverseProxy(ctx basecontext.ApiContext, rp models.ReverseProxy) (*models.ReverseProxy, error) { if !j.IsConnected() { return nil, ErrDatabaseNotConnected @@ -32,6 +60,11 @@ func (j *JsonDatabase) UpdateReverseProxy(ctx basecontext.ApiContext, rp models. if j.data.ReverseProxy.Diff(rp) { rpCopy := rp + if j.data.ReverseProxy != nil { + rpCopy.ID = j.data.ReverseProxy.ID + } else { + rpCopy.ID = helpers.GenerateId() + } j.data.ReverseProxy = &rpCopy _ = j.SaveNow(ctx) return &rp, nil diff --git a/src/mappers/reverse_proxy.go b/src/mappers/reverse_proxy.go index 6c7744c..5b7627f 100644 --- a/src/mappers/reverse_proxy.go +++ b/src/mappers/reverse_proxy.go @@ -1,9 +1,9 @@ package mappers import ( - config_models "github.com/Parallels/prl-devops-service/config" data_models "github.com/Parallels/prl-devops-service/data/models" "github.com/Parallels/prl-devops-service/models" + rp_models "github.com/Parallels/prl-devops-service/reverse_proxy/models" ) func DtoReverseProxyToApi(m data_models.ReverseProxy) models.ReverseProxy { @@ -24,10 +24,11 @@ func ApiReverseProxyToDto(m models.ReverseProxy) data_models.ReverseProxy { return r } -func ConfigReverseProxyToDto(m config_models.ReverseProxyConfig) data_models.ReverseProxy { +func ConfigReverseProxyToDto(m rp_models.ReverseProxyConfig) data_models.ReverseProxy { r := data_models.ReverseProxy{ - Host: m.Host, - Port: m.Port, + Enabled: m.Enabled, + Host: m.Host, + Port: m.Port, } return r diff --git a/src/reverse_proxy/main.go b/src/reverse_proxy/main.go index 6abe258..ef92fac 100644 --- a/src/reverse_proxy/main.go +++ b/src/reverse_proxy/main.go @@ -20,6 +20,7 @@ import ( data_models "github.com/Parallels/prl-devops-service/data/models" "github.com/Parallels/prl-devops-service/helpers" "github.com/Parallels/prl-devops-service/mappers" + "github.com/Parallels/prl-devops-service/reverse_proxy/models" "github.com/Parallels/prl-devops-service/serviceprovider" ) @@ -47,6 +48,33 @@ func Get(ctx basecontext.ApiContext) *ReverseProxyService { return globalReverseProxyService } +func GetConfig() models.ReverseProxyConfig { + cfg := config.Get() + result := models.ReverseProxyConfig{} + if cfg == nil || globalReverseProxyService == nil { + result.Enabled = false + } + + result.Host = cfg.ReverseProxyHost() + result.Port = cfg.ReverseProxyPort() + result.Enabled = cfg.IsReverseProxyEnabled() + + // Returning db data if available and not different from the config + dtoRp, _ := globalReverseProxyService.db.GetReverseProxyConfig(globalReverseProxyService.api_ctx) + if dtoRp != nil { + if !dtoRp.Diff(mappers.ConfigReverseProxyToDto(result)) { + result.Host = dtoRp.Host + result.Port = dtoRp.Port + result.Enabled = dtoRp.Enabled + result.ID = dtoRp.ID + } + + return result + } + + return result +} + func New(ctx basecontext.ApiContext) *ReverseProxyService { db, err := serviceprovider.GetDatabaseService(ctx) if err != nil { @@ -117,11 +145,48 @@ func (rps *ReverseProxyService) ImportFromConfig() error { return nil } +func (rps *ReverseProxyService) CheckChangesInConfiguration() error { + cfg := config.Get() + dtoRp, _ := rps.db.GetReverseProxyConfig(rps.api_ctx) + if dtoRp == nil && cfg.IsReverseProxyEnabled() { + dto := data_models.ReverseProxy{ + ID: helpers.GenerateId(), + Enabled: cfg.IsReverseProxyEnabled(), + Host: cfg.ReverseProxyHost(), + Port: cfg.ReverseProxyPort(), + } + if _, err := rps.db.UpdateReverseProxy(rps.api_ctx, dto); err != nil { + return err + } + + dtoRp = &dto + rps.host = dto.Host + rps.port = dto.Port + rps.api_ctx.LogDebugf("Reverse proxy configuration imported: %v", dtoRp) + } else { + configRp := GetConfig() + if dtoRp.Diff(mappers.ConfigReverseProxyToDto(configRp)) { + dto := mappers.ConfigReverseProxyToDto(GetConfig()) + if _, err := rps.db.UpdateReverseProxy(rps.api_ctx, dto); err != nil { + return err + } + } + rps.host = configRp.Host + rps.port = configRp.Port + } + + return nil +} + func (rps *ReverseProxyService) LoadFromDb() error { dtoRp, err := rps.db.GetReverseProxyConfig(rps.api_ctx) if err != nil { return err } + if dtoRp == nil { + return nil + } + rps.host = dtoRp.Host rps.port = dtoRp.Port hosts, err := rps.db.GetReverseProxyHosts(rps.api_ctx, "") @@ -162,6 +227,7 @@ func (rps *ReverseProxyService) LoadFromDb() error { } func (rps *ReverseProxyService) Start() error { + cfg := config.Get() rps.ctx, rps.cancelFunc = context.WithCancel(context.Background()) errorChan := make(chan error, 1) @@ -178,14 +244,18 @@ func (rps *ReverseProxyService) Start() error { rps.api_ctx.LogErrorf("Error loading reverse proxy config from db: %s", err) return err } + if err := rps.CheckChangesInConfiguration(); err != nil { + rps.api_ctx.LogErrorf("Error checking changes in reverse proxy config: %s", err) + return err + } if rps.port == "" { - rps.port = "8080" - rps.api_ctx.LogWarnf("[Reverse Proxy] Port not set for reverse proxy, using default port 8080") + rps.port = cfg.ReverseProxyPort() + rps.api_ctx.LogWarnf("[Reverse Proxy] Port not set for reverse proxy, using default port", rps.port) } if rps.host == "" { - rps.host = "localhost" - rps.api_ctx.LogWarnf("[Reverse Proxy] Host not set for reverse proxy, using default host localhost") + rps.host = cfg.ReverseProxyHost() + rps.api_ctx.LogWarnf("[Reverse Proxy] Host not set for reverse proxy, using default host", rps.host) } rps.api_ctx.LogInfof("[Reverse Proxy] Starting reverse proxy on %s:%s", rps.host, rps.port) @@ -208,7 +278,10 @@ func (rps *ReverseProxyService) Start() error { func (rps *ReverseProxyService) Stop() error { rps.api_ctx.LogInfof("[Reverse Proxy] Stopping reverse proxy service") - rps.cancelFunc() + // fixing a possible issue with the cancel function not being called + if rps.cancelFunc != nil { + rps.cancelFunc() + } for _, listener := range rps.tcpListeners { rps.api_ctx.LogInfof("[Reverse Proxy] [TCP Route] Closing listener") diff --git a/src/reverse_proxy/models/config.go b/src/reverse_proxy/models/config.go new file mode 100644 index 0000000..3619f6a --- /dev/null +++ b/src/reverse_proxy/models/config.go @@ -0,0 +1,8 @@ +package models + +type ReverseProxyConfig struct { + ID string `json:"-"` + Enabled bool `json:"enabled" yaml:"enabled"` + Host string `json:"host,omitempty" yaml:"host,omitempty"` + Port string `json:"port,omitempty" yaml:"port,omitempty"` +}