config.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. package config
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "os"
  8. "strings"
  9. "time"
  10. "github.com/fsnotify/fsnotify"
  11. "go.etcd.io/etcd/client"
  12. )
  13. var Conf *Configure
  14. const ConfigPath = "conf/common.json"
  15. // mysql 配置
  16. type MysqlConfig struct {
  17. User string `json:"user"`
  18. Password string `json:"password"`
  19. Addr string `json:"addr"`
  20. DefaultDB string `json:"default_db"`
  21. Charset string `json:"charset"`
  22. MaxIdle json.Number `json:"max_idle"`
  23. MaxConn json.Number `json:"max_conn"`
  24. ServiceName string `json:"service_name"`
  25. ServicePort int `json:"service_port"`
  26. }
  27. // redis 配置
  28. type RedisConfig struct {
  29. Addrs string `json:"addrs"`
  30. Password string `json:"password"`
  31. DefaultDB json.Number `json:"default_db"`
  32. PoolSize json.Number `json:"pool_size"`
  33. MinIdleConns json.Number `json:"min_idle_conns"`
  34. MaxRetries json.Number `json:"max_retries"`
  35. IsCluster string `json:"is_cluster"`
  36. }
  37. type ElasticConfig struct {
  38. Addr string `json:"addr"`
  39. Sniff string `json:"sniff"`
  40. }
  41. type WarningConfig struct {
  42. ApiTotalCountThresholds string `json:"api_total_count_thresholds"`
  43. ApiDayCountThresholds string `json:"api_day_count_thresholds"`
  44. ApiDayThresholds string `json:"api_day_thresholds"`
  45. ProviderDayCountThresholds string `json:"provider_day_count_thresholds"`
  46. DefaultMails string `json:"default_mails"`
  47. MailHost string `json:"mail_host"`
  48. MailPassword string `json:"mail_password"`
  49. MailUser string `json:"mail_user"`
  50. ApiLogAvgElapsed string `json:"api_log_avg_elapsed"`
  51. ApiLogFailThreshold string `json:"api_log_fail_threshold"`
  52. ApiLogNorecordThreshold string `json:"api_log_norecord_threshold"`
  53. ProviderLogAvgElapsed string `json:"provider_log_avg_elapsed"`
  54. ProviderLogFailThreshold string `json:"provider_log_fail_threshold"`
  55. ProviderLogNorecordThreshold string `json:"provider_log_norecord_threshold"`
  56. LogTimeInterval string `json:"log_time_interval"`
  57. }
  58. type LogConfig struct {
  59. MaxSize json.Number `json:"max_size"`
  60. MaxBackups json.Number `json:"max_backups"`
  61. MaxAge json.Number `json:"max_age"`
  62. Level string `json:"level"`
  63. DisableStacktrace string `json:"disable_stacktrace"`
  64. }
  65. type RPCNode struct {
  66. Scheme string `json:"scheme"`
  67. Name string `json:"name"`
  68. UpdateInterval json.Number `json:"update_interval"`
  69. MysqlDB string `json:"mysql_db"`
  70. RedisDB json.Number `json:"redis_db"`
  71. Log LogConfig `json:"log"`
  72. ServiceName string `json:"service_name"`
  73. ServicePort json.Number `json:"service_port"`
  74. }
  75. type RPCConfig struct {
  76. BasePath string `json:"base_path"`
  77. Crontab RPCNode `json:"gd_crontab"`
  78. Management RPCNode `json:"gd_management"`
  79. Vehicle RPCNode `json:"gd_vehicle"`
  80. }
  81. type MongoConfig struct {
  82. User string `json:"user"`
  83. Password string `json:"password"`
  84. Addr string `json:"addr"`
  85. }
  86. type ThirdPartConfig struct {
  87. HttpProxyUrl string `json:"http_proxy_url" description:"数据源正向代理url"`
  88. EdAppId string `json:"ed_app_id"` //eds16787f343c1676853
  89. EdAppSecret string `json:"ed_app_secret"` //3d3f47bef850c5a2b0c15d4b94b6b3a3
  90. C300Token string `json:"c_300_token"` //be318b5cf56c65e9172b8636699fcf17
  91. ArcbangAppId string `json:"arcbang_app_id"` //476795160986910721
  92. ArcbangAppKey string `json:"arcbang_app_key"` //897c86f2779341e88e38b3eb9acb384f
  93. NjKey string `json:"nj_key"` //E78E1F76-A9FE-4687-A3EB-198B7628D959
  94. DbDwkey string `json:"db_dwkey"` //chejinjia
  95. DbToken string `json:"db_token"` //chejinjia2017030
  96. DbEncKey string `json:"db_enc_key"` //91724890
  97. ScViolationDwkey string `json:"sc_violation_dwkey"` //be2hjdeii1f90c5c55bfa0af7
  98. ScViolationToken string `json:"sc_violation_token"` //be2hjdeii1f90c5c55bfa0af7
  99. ScViolationEncKey string `json:"sc_violation_enc_key"` //33725169
  100. MojiAppKey string `json:"moji_app_key"` //25270402
  101. MojiAppSecret string `json:"moji_app_secret"` //bc1ec844f9a516919c85c09b1c75d682
  102. MojiAppCode string `json:"moji_app_code"` //fd4df24553a04d08a71a2566203a37db
  103. LcbAppCode string `json:"lcb_app_code"` //3101
  104. LcbSecret string `json:"lcb_secret"` //b9b548a34220f097e6c22ca933f76a8e
  105. JhAppKey string `json:"jh_app_key"` //1ef0aa20c3d4cbe71f4a799122625bb9
  106. ZxCompanyKey string `json:"zx_company_key"` //001061808271603202J1I3Q1H0T2L
  107. ZxCompanyCode string `json:"zx_company_code"` //65db6e13ecef31a54642df747986472a
  108. MsToken string `json:"ms_token"` //81ed9993bcad8cd0d1f55f9565104b76
  109. ZqyKey string `json:"zqy_key"` //CETRo4r-KIkk05-uoyiE-20V7NU-Ab36
  110. ZhUser string `json:"zh_user"` //tangmimi
  111. ZhPwd string `json:"zh_pwd"` //E37A41FE3B1843E1AC46E6589CD76412
  112. ZzxAppKey string `json:"zzx_app_key"`
  113. ZzxUser string `json:"zzx_user"`
  114. ZjtAuthorizationCode string `json:"zjt_authorization_code"` //LkPw8252672h4NmF
  115. ZjtCryptoKey string `json:"zjt_crypto_key"` //Wuz2162IF9O60X58
  116. ZjtUserNo string `json:"zjt_user_no"` //SYZNCQCAR
  117. DjDwkey string `json:"dj_dwkey"` //wdhyiylhotoabycqtq
  118. DjToken string `json:"dj_token"` //MIYYKOUKIYKKKYWH081YOIYLIOJ
  119. DjEncKey string `json:"dj_enc_key"` //91724890
  120. DjScDwkey string `json:"dj_sc_dwkey"` //whsc00081890080870
  121. DjScToken string `json:"dj_sc_token"` //MIYYKOUKIYKKKYWH081YOIYLIOJ
  122. DjScEncKey string `json:"dj_sc_enc_key"` //91724890
  123. DjAppid string `json:"dj_appid"` //9225417112424
  124. DjSecrtkey string `json:"dj_secrtkey"` //IYYTOKYLHBTLIYKYQUYLHYLIY
  125. DjScAppid string `json:"dj_sc_appid"` //5524892445452455145
  126. DjScSecrtkey string `json:"dj_sc_secrtkey"` //YUOUIYOIYKHMJHUYUIOYLIYIKYIKYIJU
  127. SpyUserName string `json:"spy_user_name"`
  128. SpyPassWord string `json:"spy_pass_word"`
  129. JisuAppkey string `json:"jisu_appkey"`
  130. BjcUserName string `json:"bjc_user_name"`
  131. BjcPwd string `json:"bjc_pwd"`
  132. BjcLoginUrl string `json:"bjc_login_url"`
  133. DjVinAppid string `json:"dj_vin_appid"` //9225417112424
  134. DjVinSecrtkey string `json:"dj_vin_secrtkey"` //IYYTOKYLHBTLIYKYQUYLHYLIY
  135. C003AppCode string `json:"c003_app_code"`
  136. WarnWebhook string `json:"warn_webhook"`
  137. HystrixLoopTime int `json:"hystrix_loop_time"`
  138. }
  139. type Configure struct {
  140. RunMode string `json:"run_mode"`
  141. AppKey string `json:"app_key"`
  142. AppSecret string `json:"app_secret"`
  143. AutoExportMail string `json:"auto_export_mail"`
  144. AutoExportProviderMail string `json:"auto_export_provider_mail"`
  145. AutoExportBusinessMail string `json:"auto_export_business_mail"`
  146. ReportLocalDir string `json:"report_local_dir"`
  147. ExceptionMail string `json:"exception_mail"`
  148. LogMysql MysqlConfig `json:"log_mysql"`
  149. Redis RedisConfig `json:"redis"`
  150. Elastic ElasticConfig `json:"elastic"`
  151. //Mongo MongoConfig `json:"mongo"`
  152. Rpc RPCConfig `json:"rpc"`
  153. Warning WarningConfig `json:warning`
  154. ThirdPart ThirdPartConfig `json:"third_part"`
  155. ZqyCountIds string `json:"zqy_count_ids"`
  156. BillCreateCron string `json:"bill_create_cron"`
  157. BillNotifyCron string `json:"bill_notify_cron"`
  158. WarnPeriod json.Number `json:"warn_period" description:"告警周期(分钟)"`
  159. WarnMinCount json.Number `json:"warn_min_count" description:"告警最小统计数"`
  160. WarnSendPeriod json.Number `json:"warn_send_period" 告警发送周期(多少分钟发送异常)`
  161. }
  162. func watchEtcd(keysAPI client.KeysAPI, index uint64, runmode, key string, cli client.Client) {
  163. basePath := fmt.Sprintf("/%s/config", runmode)
  164. watcherOptions := &client.WatcherOptions{
  165. AfterIndex: index,
  166. Recursive: true,
  167. }
  168. watcher := keysAPI.Watcher(basePath, watcherOptions)
  169. for {
  170. r, err := watcher.Next(context.Background())
  171. if err != nil || r == nil {
  172. break
  173. }
  174. if r.Node != nil && r.PrevNode != nil {
  175. if r.Node.Key == r.PrevNode.Key && (r.Node.Value != r.PrevNode.Value) {
  176. reloadEtcd(runmode, key, cli)
  177. }
  178. }
  179. if r.Node != nil && r.PrevNode == nil {
  180. reloadEtcd(runmode, key, cli)
  181. }
  182. }
  183. }
  184. func reloadEtcd(runmode, key string, cli client.Client) {
  185. keysAPI := client.NewKeysAPI(cli)
  186. basePath := fmt.Sprintf("/%s/config", runmode)
  187. if resp, err := keysAPI.Get(context.Background(), basePath, &client.GetOptions{
  188. Recursive: true,
  189. }); err == nil && resp != nil && resp.Node != nil {
  190. conf := &Configure{}
  191. value := getNodeData(key, resp.Node)
  192. if jsonStr, err := json.Marshal(value); err == nil {
  193. if err := json.Unmarshal(jsonStr, &conf); err == nil {
  194. *Conf = *conf
  195. if Conf.ReportLocalDir == "" {
  196. Conf.ReportLocalDir = "/mnt/"
  197. }
  198. return
  199. } else {
  200. fmt.Printf("json Unmarshal failed. error:%s", err)
  201. }
  202. } else {
  203. fmt.Printf("json Marshal failed. error:%s", err)
  204. }
  205. } else {
  206. fmt.Printf("get %s failed. error:%s", basePath, err)
  207. }
  208. }
  209. // key 为加密密钥
  210. func GetConfig(runmode, key string, cli client.Client) *Configure {
  211. keysAPI := client.NewKeysAPI(cli)
  212. basePath := fmt.Sprintf("/%s/config", runmode)
  213. if resp, err := keysAPI.Get(context.Background(), basePath, &client.GetOptions{
  214. Recursive: true,
  215. }); err == nil && resp != nil && resp.Node != nil {
  216. Conf = &Configure{}
  217. value := getNodeData(key, resp.Node)
  218. if jsonStr, err := json.Marshal(value); err == nil {
  219. if err := json.Unmarshal(jsonStr, &Conf); err == nil {
  220. go watchEtcd(keysAPI, resp.Index, runmode, key, cli)
  221. if Conf.ReportLocalDir == "" {
  222. Conf.ReportLocalDir = "/mnt/"
  223. }
  224. return Conf
  225. } else {
  226. fmt.Printf("json Unmarshal failed. error:%s", err)
  227. }
  228. } else {
  229. fmt.Printf("json Marshal failed. error:%s", err)
  230. }
  231. } else {
  232. fmt.Printf("get %s failed. error:%s", basePath, err)
  233. os.Exit(1)
  234. }
  235. return nil
  236. }
  237. // 递归取出node的叶子节点值
  238. func getNodeData(key string, head *client.Node) (value interface{}) {
  239. s0 := strings.Split(head.Key, "/")
  240. len0 := len(s0)
  241. if len0 == 0 {
  242. return
  243. }
  244. if head.Dir {
  245. mapData := map[string]interface{}{}
  246. for _, node := range head.Nodes {
  247. s1 := strings.Split(node.Key, "/")
  248. len1 := len(s1)
  249. if len1 == 0 {
  250. break
  251. }
  252. mapData[s1[len1-1]] = getNodeData(key, node)
  253. }
  254. value = mapData
  255. } else {
  256. if key != "" && head.Value != "" {
  257. if bytesData, err := Base64URLDecode(head.Value); err != nil {
  258. fmt.Printf("Base64URLDecode(%s) failed. error:%s", head.Value, err)
  259. os.Exit(1)
  260. } else {
  261. if data, err := AesDecrypt(bytesData, []byte(key)); err != nil {
  262. fmt.Printf("AesDecrypt failed. error:%s", err)
  263. os.Exit(1)
  264. } else {
  265. value = string(data)
  266. }
  267. }
  268. } else {
  269. // 无加密,直接取值
  270. value = head.Value
  271. }
  272. }
  273. return
  274. }
  275. // 适配k8s 方式
  276. // 公共配置会以configmap的方式映射到容器的conf/common.json中
  277. func GetConfigForK8s() *Configure {
  278. buffer, err := ioutil.ReadFile(ConfigPath)
  279. if err != nil {
  280. fmt.Printf("get %s failed. error:%s", ConfigPath, err)
  281. return nil
  282. }
  283. Conf = &Configure{}
  284. if err := json.Unmarshal(buffer, Conf); err != nil {
  285. fmt.Printf("json Unmarshal failed. error:%s", err)
  286. return nil
  287. }
  288. if Conf.ReportLocalDir == "" {
  289. Conf.ReportLocalDir = "/mnt/"
  290. }
  291. go watchConfigFileForK8s()
  292. return Conf
  293. }
  294. func ReloadConfigForK8s() {
  295. buffer, err := ioutil.ReadFile(ConfigPath)
  296. if err != nil {
  297. fmt.Printf("get %s failed. error:%s", ConfigPath, err)
  298. }
  299. confTmp := &Configure{}
  300. if err := json.Unmarshal(buffer, confTmp); err != nil {
  301. fmt.Printf("json Unmarshal failed. error:%s", err)
  302. }
  303. Conf = confTmp
  304. if Conf.ReportLocalDir == "" {
  305. Conf.ReportLocalDir = "/mnt/"
  306. }
  307. }
  308. // 判断路径文件/文件夹是否存在
  309. func Exists(path string) bool {
  310. _, err := os.Stat(path)
  311. if err != nil {
  312. if os.IsExist(err) {
  313. return true
  314. }
  315. return false
  316. }
  317. return true
  318. }
  319. func watchConfigFileForK8s() {
  320. fileExist := true
  321. watch, err := fsnotify.NewWatcher()
  322. if err != nil {
  323. fmt.Printf("new file watcher failed\n\n")
  324. os.Exit(1)
  325. }
  326. defer watch.Close()
  327. /*err = watch.Add(ConfigPath)
  328. if err != nil {
  329. fmt.Printf("add file watcher failed\n\n")
  330. os.Exit(1)
  331. }*/
  332. for {
  333. // 判断文件是否存在
  334. if !Exists(ConfigPath) {
  335. time.Sleep(10 * time.Second)
  336. fileExist = false
  337. continue
  338. } else {
  339. watch.Remove(ConfigPath)
  340. watch.Add(ConfigPath)
  341. if !fileExist { // 文件重新创建
  342. ReloadConfigForK8s()
  343. }
  344. fileExist = true
  345. }
  346. select {
  347. case ev := <-watch.Events:
  348. {
  349. fmt.Println("op : ", ev.Op)
  350. ReloadConfigForK8s()
  351. }
  352. case err := <-watch.Errors:
  353. {
  354. fmt.Println("error : ", err)
  355. continue
  356. }
  357. }
  358. }
  359. }