config.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. package guerrilla
  2. import (
  3. "crypto/tls"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "os"
  8. "reflect"
  9. "strings"
  10. )
  11. // AppConfig is the holder of the configuration of the app
  12. type AppConfig struct {
  13. Servers []ServerConfig `json:"servers"`
  14. AllowedHosts []string `json:"allowed_hosts"`
  15. PidFile string `json:"pid_file"`
  16. LogFile string `json:"log_file,omitempty"`
  17. LogLevel string `json:"log_level,omitempty"`
  18. }
  19. // ServerConfig specifies config options for a single server
  20. type ServerConfig struct {
  21. IsEnabled bool `json:"is_enabled"`
  22. Hostname string `json:"host_name"`
  23. MaxSize int64 `json:"max_size"`
  24. PrivateKeyFile string `json:"private_key_file"`
  25. PublicKeyFile string `json:"public_key_file"`
  26. Timeout int `json:"timeout"`
  27. ListenInterface string `json:"listen_interface"`
  28. StartTLSOn bool `json:"start_tls_on,omitempty"`
  29. TLSAlwaysOn bool `json:"tls_always_on,omitempty"`
  30. MaxClients int `json:"max_clients"`
  31. LogFile string `json:"log_file,omitempty"`
  32. _privateKeyFile_mtime int
  33. _publicKeyFile_mtime int
  34. }
  35. // Unmarshalls json data into AppConfig struct and any other initialization of the struct
  36. // also does validation, returns error if validation failed or something went wrong
  37. func (c *AppConfig) Load(jsonBytes []byte) error {
  38. err := json.Unmarshal(jsonBytes, c)
  39. if err != nil {
  40. return fmt.Errorf("could not parse config file: %s", err)
  41. }
  42. if len(c.AllowedHosts) == 0 {
  43. return errors.New("empty AllowedHosts is not allowed")
  44. }
  45. // all servers must be valid in order to continue
  46. for _, server := range c.Servers {
  47. if errs := server.Validate(); errs != nil {
  48. return errs
  49. }
  50. }
  51. // read the timestamps for the ssl keys, to determine if they need to be reloaded
  52. for i := 0; i < len(c.Servers); i++ {
  53. c.Servers[i].loadTlsKeyTimestamps()
  54. }
  55. return nil
  56. }
  57. // Emits any configuration change events onto the event bus.
  58. func (c *AppConfig) EmitChangeEvents(oldConfig *AppConfig, app Guerrilla) {
  59. // has config changed, general check
  60. if !reflect.DeepEqual(oldConfig, c) {
  61. app.Publish(EventConfigNewConfig, c)
  62. }
  63. // has 'allowed hosts' changed?
  64. if !reflect.DeepEqual(oldConfig.AllowedHosts, c.AllowedHosts) {
  65. app.Publish(EventConfigAllowedHosts, c)
  66. }
  67. // has pid file changed?
  68. if strings.Compare(oldConfig.PidFile, c.PidFile) != 0 {
  69. app.Publish(EventConfigPidFile, c)
  70. }
  71. // has mainlog log changed?
  72. if strings.Compare(oldConfig.LogFile, c.LogFile) != 0 {
  73. app.Publish(EventConfigLogFile, c)
  74. } else {
  75. // since config file has not changed, we reload it
  76. app.Publish(EventConfigLogReopen, c)
  77. }
  78. // has log level changed?
  79. if strings.Compare(oldConfig.LogLevel, c.LogLevel) != 0 {
  80. app.Publish(EventConfigLogLevel, c)
  81. }
  82. // server config changes
  83. oldServers := oldConfig.getServers()
  84. for iface, newServer := range c.getServers() {
  85. // is server is in both configs?
  86. if oldServer, ok := oldServers[iface]; ok {
  87. // since old server exists in the new config, we do not track it anymore
  88. delete(oldServers, iface)
  89. // so we know the server exists in both old & new configs
  90. newServer.emitChangeEvents(oldServer, app)
  91. } else {
  92. // start new server
  93. app.Publish(EventConfigServerNew, newServer)
  94. }
  95. }
  96. // remove any servers that don't exist anymore
  97. for _, oldserver := range oldServers {
  98. app.Publish(EventConfigServerRemove, oldserver)
  99. }
  100. }
  101. // EmitLogReopen emits log reopen events using existing config
  102. func (c *AppConfig) EmitLogReopenEvents(app Guerrilla) {
  103. app.Publish(EventConfigLogReopen, c)
  104. for _, sc := range c.getServers() {
  105. app.Publish(EventConfigServerLogReopen, sc)
  106. }
  107. }
  108. // gets the servers in a map (key by interface) for easy lookup
  109. func (c *AppConfig) getServers() map[string]*ServerConfig {
  110. servers := make(map[string]*ServerConfig, len(c.Servers))
  111. for i := 0; i < len(c.Servers); i++ {
  112. servers[c.Servers[i].ListenInterface] = &c.Servers[i]
  113. }
  114. return servers
  115. }
  116. // Emits any configuration change events on the server.
  117. // All events are fired and run synchronously
  118. func (sc *ServerConfig) emitChangeEvents(oldServer *ServerConfig, app Guerrilla) {
  119. // get a list of changes
  120. changes := getDiff(
  121. *oldServer,
  122. *sc,
  123. )
  124. if len(changes) > 0 {
  125. // something changed in the server config
  126. app.Publish(EventConfigServerConfig, sc)
  127. }
  128. // enable or disable?
  129. if _, ok := changes["IsEnabled"]; ok {
  130. if sc.IsEnabled {
  131. app.Publish(EventConfigServerStart, sc)
  132. } else {
  133. app.Publish(EventConfigServerStop, sc)
  134. }
  135. // do not emit any more events when IsEnabled changed
  136. return
  137. }
  138. // log file change?
  139. if _, ok := changes["LogFile"]; ok {
  140. app.Publish(EventConfigServerLogFile, sc)
  141. } else {
  142. // since config file has not changed, we reload it
  143. app.Publish(EventConfigServerLogReopen, sc)
  144. }
  145. // timeout changed
  146. if _, ok := changes["Timeout"]; ok {
  147. app.Publish(EventConfigServerTimeout, sc)
  148. }
  149. // max_clients changed
  150. if _, ok := changes["MaxClients"]; ok {
  151. app.Publish(EventConfigServerMaxClients, sc)
  152. }
  153. // tls changed
  154. if ok := func() bool {
  155. if _, ok := changes["PrivateKeyFile"]; ok {
  156. return true
  157. }
  158. if _, ok := changes["PublicKeyFile"]; ok {
  159. return true
  160. }
  161. if _, ok := changes["StartTLSOn"]; ok {
  162. return true
  163. }
  164. if _, ok := changes["TLSAlwaysOn"]; ok {
  165. return true
  166. }
  167. return false
  168. }(); ok {
  169. app.Publish(EventConfigServerTLSConfig, sc)
  170. }
  171. }
  172. // Loads in timestamps for the ssl keys
  173. func (sc *ServerConfig) loadTlsKeyTimestamps() error {
  174. var statErr = func(iface string, err error) error {
  175. return errors.New(
  176. fmt.Sprintf(
  177. "could not stat key for server [%s], %s",
  178. iface,
  179. err.Error()))
  180. }
  181. if info, err := os.Stat(sc.PrivateKeyFile); err == nil {
  182. sc._privateKeyFile_mtime = info.ModTime().Second()
  183. } else {
  184. return statErr(sc.ListenInterface, err)
  185. }
  186. if info, err := os.Stat(sc.PublicKeyFile); err == nil {
  187. sc._publicKeyFile_mtime = info.ModTime().Second()
  188. } else {
  189. return statErr(sc.ListenInterface, err)
  190. }
  191. return nil
  192. }
  193. // Gets the timestamp of the TLS certificates. Returns a unix time of when they were last modified
  194. // when the config was read. We use this info to determine if TLS needs to be re-loaded.
  195. func (sc *ServerConfig) getTlsKeyTimestamps() (int, int) {
  196. return sc._privateKeyFile_mtime, sc._publicKeyFile_mtime
  197. }
  198. // Validate validates the server's configuration.
  199. func (sc *ServerConfig) Validate() Errors {
  200. var errs Errors
  201. if _, err := tls.LoadX509KeyPair(sc.PublicKeyFile, sc.PrivateKeyFile); err != nil {
  202. if sc.StartTLSOn || sc.TLSAlwaysOn {
  203. errs = append(errs,
  204. errors.New(fmt.Sprintf("cannot use TLS config for [%s], %v", sc.ListenInterface, err)))
  205. }
  206. }
  207. return errs
  208. }
  209. // Returns a diff between struct a & struct b.
  210. // Results are returned in a map, where each key is the name of the field that was different.
  211. // a and b are struct values, must not be pointer
  212. // and of the same struct type
  213. func getDiff(a interface{}, b interface{}) map[string]interface{} {
  214. ret := make(map[string]interface{}, 5)
  215. compareWith := structtomap(b)
  216. for key, val := range structtomap(a) {
  217. if val != compareWith[key] {
  218. ret[key] = compareWith[key]
  219. }
  220. }
  221. // detect tls changes (have the key files been modified?)
  222. if oldServer, ok := a.(ServerConfig); ok {
  223. t1, t2 := oldServer.getTlsKeyTimestamps()
  224. if newServer, ok := b.(ServerConfig); ok {
  225. t3, t4 := newServer.getTlsKeyTimestamps()
  226. if t1 != t3 {
  227. ret["PrivateKeyFile"] = newServer.PrivateKeyFile
  228. }
  229. if t2 != t4 {
  230. ret["PublicKeyFile"] = newServer.PublicKeyFile
  231. }
  232. }
  233. }
  234. return ret
  235. }
  236. // Convert fields of a struct to a map
  237. // only able to convert int, bool and string; not recursive
  238. func structtomap(obj interface{}) map[string]interface{} {
  239. ret := make(map[string]interface{}, 0)
  240. v := reflect.ValueOf(obj)
  241. t := v.Type()
  242. for index := 0; index < v.NumField(); index++ {
  243. vField := v.Field(index)
  244. fName := t.Field(index).Name
  245. switch vField.Kind() {
  246. case reflect.Int:
  247. value := vField.Int()
  248. ret[fName] = value
  249. case reflect.String:
  250. value := vField.String()
  251. ret[fName] = value
  252. case reflect.Bool:
  253. value := vField.Bool()
  254. ret[fName] = value
  255. }
  256. }
  257. return ret
  258. }