data_funcs.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. package config
  2. import (
  3. yaml "github.com/cloudfoundry-incubator/candiedyaml"
  4. "github.com/rancher/os/log"
  5. "strings"
  6. "github.com/rancher/os/util"
  7. )
  8. type CfgFunc func(*CloudConfig) (*CloudConfig, error)
  9. type CfgFuncData struct {
  10. Name string
  11. Func CfgFunc
  12. }
  13. type CfgFuncs []CfgFuncData
  14. func ChainCfgFuncs(cfg *CloudConfig, cfgFuncs CfgFuncs) (*CloudConfig, error) {
  15. len := len(cfgFuncs)
  16. for c, d := range cfgFuncs {
  17. i := c + 1
  18. name := d.Name
  19. cfgFunc := d.Func
  20. if cfg == nil {
  21. log.Infof("[%d/%d] Starting %s WITH NIL cfg", i, len, name)
  22. } else {
  23. log.Infof("[%d/%d] Starting %s", i, len, name)
  24. }
  25. var err error
  26. if cfg, err = cfgFunc(cfg); err != nil {
  27. log.Errorf("Failed [%d/%d] %s: %s", i, len, name, err)
  28. return cfg, err
  29. }
  30. log.Debugf("[%d/%d] Done %s", i, len, name)
  31. }
  32. return cfg, nil
  33. }
  34. func filterKey(data map[interface{}]interface{}, key []string) (filtered, rest map[interface{}]interface{}) {
  35. if len(key) == 0 {
  36. return data, map[interface{}]interface{}{}
  37. }
  38. filtered = map[interface{}]interface{}{}
  39. rest = util.MapCopy(data)
  40. k := key[0]
  41. if d, ok := data[k]; ok {
  42. switch d := d.(type) {
  43. case map[interface{}]interface{}:
  44. f, r := filterKey(d, key[1:])
  45. if len(f) != 0 {
  46. filtered[k] = f
  47. }
  48. if len(r) != 0 {
  49. rest[k] = r
  50. } else {
  51. delete(rest, k)
  52. }
  53. default:
  54. filtered[k] = d
  55. delete(rest, k)
  56. }
  57. }
  58. return
  59. }
  60. func filterPrivateKeys(data map[interface{}]interface{}) map[interface{}]interface{} {
  61. for _, privateKey := range PrivateKeys {
  62. _, data = filterKey(data, strings.Split(privateKey, "."))
  63. }
  64. return data
  65. }
  66. func getOrSetVal(args string, data map[interface{}]interface{}, value interface{}) (interface{}, map[interface{}]interface{}) {
  67. parts := strings.Split(args, ".")
  68. tData := data
  69. if value != nil {
  70. tData = util.MapCopy(data)
  71. }
  72. t := tData
  73. for i, part := range parts {
  74. val, ok := t[part]
  75. last := i+1 == len(parts)
  76. // Reached end, set the value
  77. if last && value != nil {
  78. if s, ok := value.(string); ok {
  79. value = unmarshalOrReturnString(s)
  80. }
  81. t[part] = value
  82. return value, tData
  83. }
  84. // Missing intermediate key, create key
  85. if !last && value != nil && !ok {
  86. newData := map[interface{}]interface{}{}
  87. t[part] = newData
  88. t = newData
  89. continue
  90. }
  91. if !ok {
  92. break
  93. }
  94. if last {
  95. return val, tData
  96. }
  97. newData, ok := val.(map[interface{}]interface{})
  98. if !ok {
  99. break
  100. }
  101. t = newData
  102. }
  103. return "", tData
  104. }
  105. // Replace newlines, colons, and question marks with random strings
  106. // This is done to avoid YAML treating these as special characters
  107. var (
  108. newlineMagicString = "9XsJcx6dR5EERYCC"
  109. colonMagicString = "V0Rc21pIVknMm2rr"
  110. questionMarkMagicString = "FoPL6JLMAaJqKMJT"
  111. )
  112. func reverseReplacement(result interface{}) interface{} {
  113. switch val := result.(type) {
  114. case map[interface{}]interface{}:
  115. for k, v := range val {
  116. val[k] = reverseReplacement(v)
  117. }
  118. return val
  119. case []interface{}:
  120. for i, item := range val {
  121. val[i] = reverseReplacement(item)
  122. }
  123. return val
  124. case string:
  125. val = strings.Replace(val, newlineMagicString, "\n", -1)
  126. val = strings.Replace(val, colonMagicString, ":", -1)
  127. val = strings.Replace(val, questionMarkMagicString, "?", -1)
  128. return val
  129. }
  130. return result
  131. }
  132. func unmarshalOrReturnString(value string) (result interface{}) {
  133. value = strings.Replace(value, "\n", newlineMagicString, -1)
  134. value = strings.Replace(value, ":", colonMagicString, -1)
  135. value = strings.Replace(value, "?", questionMarkMagicString, -1)
  136. if err := yaml.Unmarshal([]byte(value), &result); err != nil {
  137. result = value
  138. }
  139. result = reverseReplacement(result)
  140. return
  141. }
  142. func parseCmdline(cmdLine string) map[interface{}]interface{} {
  143. result := make(map[interface{}]interface{})
  144. outer:
  145. for _, part := range strings.Split(cmdLine, " ") {
  146. if strings.HasPrefix(part, "cc.") {
  147. part = part[3:]
  148. } else if !strings.HasPrefix(part, "rancher.") {
  149. continue
  150. }
  151. var value string
  152. kv := strings.SplitN(part, "=", 2)
  153. if len(kv) == 1 {
  154. value = "true"
  155. } else {
  156. value = kv[1]
  157. }
  158. current := result
  159. keys := strings.Split(kv[0], ".")
  160. for i, key := range keys {
  161. if i == len(keys)-1 {
  162. current[key] = unmarshalOrReturnString(value)
  163. } else {
  164. if obj, ok := current[key]; ok {
  165. if newCurrent, ok := obj.(map[interface{}]interface{}); ok {
  166. current = newCurrent
  167. } else {
  168. continue outer
  169. }
  170. } else {
  171. newCurrent := make(map[interface{}]interface{})
  172. current[key] = newCurrent
  173. current = newCurrent
  174. }
  175. }
  176. }
  177. }
  178. return result
  179. }