diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 9d53092a6..37fcfde2c 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -508,6 +508,9 @@ func main() { if len(cfg.HTTPCfg().DispatchersRegistrarURL) != 0 { server.RegisterHttpFunc(cfg.HTTPCfg().DispatchersRegistrarURL, dispatcherh.Registar) } + if len(cfg.HTTPCfg().Configs) != 0 { + server.RegisterHttpFunc(cfg.HTTPCfg().Configs, config.HandlerConfigS) + } if *httpPprofPath != "" { go server.RegisterProfiler(*httpPprofPath) } diff --git a/config/config.go b/config/config.go index fcda4932a..a2184f257 100755 --- a/config/config.go +++ b/config/config.go @@ -189,7 +189,6 @@ func NewDefaultCGRConfig() (cfg *CGRConfig, err error) { cfg.eesCfg.Cache = make(map[string]*CacheParamCfg) cfg.rateSCfg = new(RateSCfg) cfg.sipAgentCfg = new(SIPAgentCfg) - cfg.configSCfg = new(ConfigSCfg) cfg.ConfigReloads = make(map[string]chan struct{}) @@ -312,7 +311,6 @@ type CGRConfig struct { eesCfg *EEsCfg // EventExporter config rateSCfg *RateSCfg // RateS config sipAgentCfg *SIPAgentCfg // SIPAgent config - configSCfg *ConfigSCfg //ConfigS config } var posibleLoaderTypes = utils.NewStringSet([]string{utils.MetaAttributes, @@ -378,7 +376,7 @@ func (cfg *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { cfg.loadMailerCfg, cfg.loadSureTaxCfg, cfg.loadDispatcherSCfg, cfg.loadLoaderCgrCfg, cfg.loadMigratorCgrCfg, cfg.loadTlsCgrCfg, cfg.loadAnalyzerCgrCfg, cfg.loadApierCfg, cfg.loadErsCfg, cfg.loadEesCfg, - cfg.loadRateSCfg, cfg.loadSIPAgentCfg, cfg.loadDispatcherHCfg, cfg.loadConfigSCfg} { + cfg.loadRateSCfg, cfg.loadSIPAgentCfg, cfg.loadDispatcherHCfg} { if err = loadFunc(jsnCfg); err != nil { return } @@ -779,14 +777,6 @@ func (cfg *CGRConfig) loadTemplateSCfg(jsnCfg *CgrJsonCfg) (err error) { return } -func (cfg *CGRConfig) loadConfigSCfg(jsnCfg *CgrJsonCfg) (err error) { - var jsnConfigSCfg *ConfigSCfgJson - if jsnConfigSCfg, err = jsnCfg.ConfigSJsonCfg(); err != nil { - return - } - return cfg.configSCfg.loadFromJsonCfg(jsnConfigSCfg) -} - // SureTaxCfg use locking to retrieve the configuration, possibility later for runtime reload func (cfg *CGRConfig) SureTaxCfg() *SureTaxCfg { cfg.lks[SURETAX_JSON].Lock() @@ -1292,7 +1282,6 @@ func (cfg *CGRConfig) getLoadFunctions() map[string]func(*CgrJsonCfg) error { RateSJson: cfg.loadRateSCfg, SIPAgentJson: cfg.loadSIPAgentCfg, TemplatesJson: cfg.loadTemplateSCfg, - ConfigSJson: cfg.loadConfigSCfg, } } @@ -1629,3 +1618,68 @@ func (cfg *CGRConfig) AsMapInterface(separator string) map[string]interface{} { utils.ErsCfg: cfg.ersCfg.AsMapInterface(separator), } } + +// RegisterConfigs handler for httpServer to register the configs +func HandlerConfigS(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + w.Header().Set("Content-Type", "application/json") + // check if the path exists + fi, err := os.Stat(r.URL.Path) + if err != nil { + if os.IsNotExist(err) { + w.WriteHeader(404) + } else { + w.WriteHeader(500) + } + fmt.Fprintf(w, err.Error()) + return + } + switch mode := fi.Mode(); { + case mode.IsDir(): + handleConfigSFolder(r.URL.Path, w) + case mode.IsRegular(): + handleConfigSFile(r.URL.Path, w) + } + return +} + +func handleConfigSFolder(path string, w http.ResponseWriter) { + // if the path is a directory, read the directory, construct the config and load it in memory + cfg, err := NewCGRConfigFromPath(path) + if err != nil { + if err.Error() == utils.ErrPathNotReachable(path).Error() { // if we receive path error change the header of response to 404 Error NotFound + w.WriteHeader(404) + } else { + w.WriteHeader(500) + } + fmt.Fprintf(w, err.Error()) + return + } + // convert the config into a json and send it + if _, err := w.Write([]byte(utils.ToJSON(cfg.AsMapInterface))); err != nil { + utils.Logger.Warning(fmt.Sprintf("<%s> Failed to write resonse because: %s", + utils.Configs, err)) + } + return +} + +func handleConfigSFile(path string, w http.ResponseWriter) { + // if the config is a file read the file and send it directly + f, err := os.Open(path) + if err != nil { + w.WriteHeader(404) + fmt.Fprintf(w, err.Error()) + return + } + var b []byte + if _, err := io.ReadFull(f, b); err != nil { + w.WriteHeader(500) + fmt.Fprintf(w, err.Error()) + return + } + if _, err := w.Write(b); err != nil { + utils.Logger.Warning(fmt.Sprintf("<%s> Failed to write resonse because: %s", + utils.Configs, err)) + } + return +} diff --git a/config/config_defaults.go b/config/config_defaults.go index 06fceada7..c4feb63d5 100755 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -185,6 +185,7 @@ const CGRATES_CFG_JSON = ` "http_cdrs": "/cdr_http", // CDRS relative URL ("" to disable) "use_basic_auth": false, // use basic authentication "auth_users": {}, // basic authentication usernames and base64-encoded passwords (eg: { "username1": "cGFzc3dvcmQ=", "username2": "cGFzc3dvcmQy "}) + "configs": "/configs" // configs }, @@ -989,12 +990,4 @@ const CGRATES_CFG_JSON = ` "value": "SIP/2.0 500 Internal Server Error", "mandatory": true}, ], }, - - -"configs": { - "enabled": false, // enables the ConfigS: - "listen": "", // address where to listen for config -}, - - }` diff --git a/config/config_json.go b/config/config_json.go index 6e7264748..59e9bac68 100644 --- a/config/config_json.go +++ b/config/config_json.go @@ -63,7 +63,6 @@ const ( RPCConnsJsonName = "rpc_conns" SIPAgentJson = "sip_agent" TemplatesJson = "templates" - ConfigSJson = "configs" ) var ( @@ -71,7 +70,7 @@ var ( CACHE_JSN, FilterSjsn, RALS_JSN, CDRS_JSN, ERsJson, SessionSJson, AsteriskAgentJSN, FreeSWITCHAgentJSN, KamailioAgentJSN, DA_JSN, RA_JSN, HttpAgentJson, DNSAgentJson, ATTRIBUTE_JSN, ChargerSCfgJson, RESOURCES_JSON, STATS_JSON, THRESHOLDS_JSON, RouteSJson, LoaderJson, MAILER_JSN, SURETAX_JSON, CgrLoaderCfgJson, CgrMigratorCfgJson, DispatcherSJson, - AnalyzerCfgJson, ApierS, EEsJson, RateSJson, SIPAgentJson, DispatcherHJson, TemplatesJson, ConfigSJson} + AnalyzerCfgJson, ApierS, EEsJson, RateSJson, SIPAgentJson, DispatcherHJson, TemplatesJson} ) // Loads the json config out of io.Reader, eg other sources than file, maybe over http @@ -545,15 +544,3 @@ func (self CgrJsonCfg) TemplateSJsonCfg() (map[string][]*FcTemplateJsonCfg, erro } return cfg, nil } - -func (self CgrJsonCfg) ConfigSJsonCfg() (*ConfigSCfgJson, error) { - rawCfg, hasKey := self[ConfigSJson] - if !hasKey { - return nil, nil - } - cfg := new(ConfigSCfgJson) - if err := json.Unmarshal(*rawCfg, cfg); err != nil { - return nil, err - } - return cfg, nil -} diff --git a/config/config_json_test.go b/config/config_json_test.go index 18b07c09b..abe0e391d 100755 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -1557,6 +1557,7 @@ func TestDfHttpJsonCfg(t *testing.T) { Http_Cdrs: utils.StringPointer("/cdr_http"), Use_basic_auth: utils.BoolPointer(false), Auth_users: utils.MapStringStringPointer(map[string]string{}), + Configs: utils.StringPointer("/configs"), } if cfg, err := dfCgrJSONCfg.HttpJsonCfg(); err != nil { t.Error(err) diff --git a/config/config_test.go b/config/config_test.go index 28da009b0..13a59321c 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -2491,14 +2491,3 @@ func TestRpcConnsDefaults(t *testing.T) { t.Errorf("received: %+v,\n expecting: %+v", utils.ToJSON(cgrCfg.rpcConns), utils.ToJSON(eCfg)) } } - -func TestCgrCfgJSONDefaultsConfigS(t *testing.T) { - eCfg := &ConfigSCfg{ - Enabled: false, - Listen: utils.EmptyString, - } - - if !reflect.DeepEqual(cgrCfg.configSCfg, eCfg) { - t.Errorf("received: %+v, expecting: %+v", utils.ToJSON(cgrCfg.configSCfg), utils.ToJSON(eCfg)) - } -} diff --git a/config/configs.go b/config/configs.go deleted file mode 100644 index 6e7697d59..000000000 --- a/config/configs.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package config - -// ConfigSCfg config for listening over http -type ConfigSCfg struct { - Enabled bool - Listen string -} - -//loadFromJsonCfg loads Database config from JsonCfg -func (cScfg *ConfigSCfg) loadFromJsonCfg(jsnCfg *ConfigSCfgJson) (err error) { - if jsnCfg == nil { - return nil - } - if jsnCfg.Enabled != nil { - cScfg.Enabled = *jsnCfg.Enabled - } - if jsnCfg.Listen != nil { - cScfg.Listen = *jsnCfg.Listen - } - return -} diff --git a/config/httpcfg.go b/config/httpcfg.go index 420dd0ba0..c0fdf2be7 100644 --- a/config/httpcfg.go +++ b/config/httpcfg.go @@ -29,6 +29,7 @@ type HTTPCfg struct { HTTPCDRsURL string // CDRS relative URL ("" to disable) HTTPUseBasicAuth bool // Use basic auth for HTTP API HTTPAuthUsers map[string]string // Basic auth user:password map (base64 passwords) + Configs string } //loadFromJsonCfg loads Database config from JsonCfg @@ -57,6 +58,9 @@ func (httpcfg *HTTPCfg) loadFromJsonCfg(jsnHttpCfg *HTTPJsonCfg) (err error) { if jsnHttpCfg.Auth_users != nil { httpcfg.HTTPAuthUsers = *jsnHttpCfg.Auth_users } + if jsnHttpCfg.Configs != nil { + httpcfg.Configs = *jsnHttpCfg.Configs + } return nil } @@ -75,5 +79,6 @@ func (httpcfg *HTTPCfg) AsMapInterface() map[string]interface{} { utils.HTTPCDRsURLCfg: httpcfg.HTTPCDRsURL, utils.HTTPUseBasicAuthCfg: httpcfg.HTTPUseBasicAuth, utils.HTTPAuthUsersCfg: httpUsers, + utils.Configs: httpcfg.Configs, } } diff --git a/config/httpcfg_test.go b/config/httpcfg_test.go index 5bcc4d882..9af7613dc 100644 --- a/config/httpcfg_test.go +++ b/config/httpcfg_test.go @@ -75,7 +75,8 @@ func TestHTTPCfgAsMapInterface(t *testing.T) { "freeswitch_cdrs_url": "/freeswitch_json", "http_cdrs": "/cdr_http", "use_basic_auth": false, - "auth_users": {}, + "auth_users": {}, + "configs": "/configs" }, }` @@ -87,6 +88,7 @@ func TestHTTPCfgAsMapInterface(t *testing.T) { "http_cdrs": "/cdr_http", "use_basic_auth": false, "auth_users": map[string]interface{}{}, + "configs": "/configs", } if jsnCfg, err := NewCgrJsonCfgFromBytes([]byte(cfgJSONStr)); err != nil { diff --git a/config/libconfig_json.go b/config/libconfig_json.go index 3ce5ea78b..fde261534 100755 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -71,6 +71,7 @@ type HTTPJsonCfg struct { Http_Cdrs *string Use_basic_auth *bool Auth_users *map[string]string + Configs *string } type TlsJsonCfg struct { diff --git a/utils/consts.go b/utils/consts.go index 1fa5553a7..6ddb56e25 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -1939,6 +1939,7 @@ const ( HTTPCDRsURLCfg = "http_cdrs" HTTPUseBasicAuthCfg = "use_basic_auth" HTTPAuthUsersCfg = "auth_users" + Configs = "configs" ) // FilterSCfg