data_funcs.go 4.1 KB

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