values.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Package values is a set of value types to use in provisioning. They add custom unmarshaling logic that puts the string values
  2. // through os.ExpandEnv.
  3. // Usage:
  4. // type Data struct {
  5. // Field StringValue `yaml:"field"` // Instead of string
  6. // }
  7. // d := &Data{}
  8. // // unmarshal into d
  9. // d.Field.Value() // returns the final interpolated value from the yaml file
  10. //
  11. package values
  12. import (
  13. "os"
  14. "reflect"
  15. "strconv"
  16. "strings"
  17. "github.com/grafana/grafana/pkg/util/errutil"
  18. )
  19. type IntValue struct {
  20. value int
  21. Raw string
  22. }
  23. func (val *IntValue) UnmarshalYAML(unmarshal func(interface{}) error) error {
  24. interpolated, err := getInterpolated(unmarshal)
  25. if err != nil {
  26. return err
  27. }
  28. if len(interpolated.value) == 0 {
  29. // To keep the same behaviour as the yaml lib which just does not set the value if it is empty.
  30. return nil
  31. }
  32. val.Raw = interpolated.raw
  33. val.value, err = strconv.Atoi(interpolated.value)
  34. return errutil.Wrap("cannot convert value int", err)
  35. }
  36. func (val *IntValue) Value() int {
  37. return val.value
  38. }
  39. type Int64Value struct {
  40. value int64
  41. Raw string
  42. }
  43. func (val *Int64Value) UnmarshalYAML(unmarshal func(interface{}) error) error {
  44. interpolated, err := getInterpolated(unmarshal)
  45. if err != nil {
  46. return err
  47. }
  48. if len(interpolated.value) == 0 {
  49. // To keep the same behaviour as the yaml lib which just does not set the value if it is empty.
  50. return nil
  51. }
  52. val.Raw = interpolated.raw
  53. val.value, err = strconv.ParseInt(interpolated.value, 10, 64)
  54. return err
  55. }
  56. func (val *Int64Value) Value() int64 {
  57. return val.value
  58. }
  59. type StringValue struct {
  60. value string
  61. Raw string
  62. }
  63. func (val *StringValue) UnmarshalYAML(unmarshal func(interface{}) error) error {
  64. interpolated, err := getInterpolated(unmarshal)
  65. if err != nil {
  66. return err
  67. }
  68. val.Raw = interpolated.raw
  69. val.value = interpolated.value
  70. return err
  71. }
  72. func (val *StringValue) Value() string {
  73. return val.value
  74. }
  75. type BoolValue struct {
  76. value bool
  77. Raw string
  78. }
  79. func (val *BoolValue) UnmarshalYAML(unmarshal func(interface{}) error) error {
  80. interpolated, err := getInterpolated(unmarshal)
  81. if err != nil {
  82. return err
  83. }
  84. val.Raw = interpolated.raw
  85. val.value, err = strconv.ParseBool(interpolated.value)
  86. return err
  87. }
  88. func (val *BoolValue) Value() bool {
  89. return val.value
  90. }
  91. type JSONValue struct {
  92. value map[string]interface{}
  93. Raw map[string]interface{}
  94. }
  95. func (val *JSONValue) UnmarshalYAML(unmarshal func(interface{}) error) error {
  96. unmarshaled := make(map[string]interface{})
  97. err := unmarshal(unmarshaled)
  98. if err != nil {
  99. return err
  100. }
  101. val.Raw = unmarshaled
  102. interpolated := make(map[string]interface{})
  103. for key, val := range unmarshaled {
  104. interpolated[key] = tranformInterface(val)
  105. }
  106. val.value = interpolated
  107. return err
  108. }
  109. func (val *JSONValue) Value() map[string]interface{} {
  110. return val.value
  111. }
  112. type StringMapValue struct {
  113. value map[string]string
  114. Raw map[string]string
  115. }
  116. func (val *StringMapValue) UnmarshalYAML(unmarshal func(interface{}) error) error {
  117. unmarshaled := make(map[string]string)
  118. err := unmarshal(unmarshaled)
  119. if err != nil {
  120. return err
  121. }
  122. val.Raw = unmarshaled
  123. interpolated := make(map[string]string)
  124. for key, val := range unmarshaled {
  125. interpolated[key] = interpolateValue(val)
  126. }
  127. val.value = interpolated
  128. return err
  129. }
  130. func (val *StringMapValue) Value() map[string]string {
  131. return val.value
  132. }
  133. // tranformInterface tries to transform any interface type into proper value with env expansion. It travers maps and
  134. // slices and the actual interpolation is done on all simple string values in the structure. It returns a copy of any
  135. // map or slice value instead of modifying them in place.
  136. func tranformInterface(i interface{}) interface{} {
  137. switch reflect.TypeOf(i).Kind() {
  138. case reflect.Slice:
  139. return transformSlice(i.([]interface{}))
  140. case reflect.Map:
  141. return transformMap(i.(map[interface{}]interface{}))
  142. case reflect.String:
  143. return interpolateValue(i.(string))
  144. default:
  145. // Was int, float or some other value that we do not need to do any transform on.
  146. return i
  147. }
  148. }
  149. func transformSlice(i []interface{}) interface{} {
  150. var transformed []interface{}
  151. for _, val := range i {
  152. transformed = append(transformed, tranformInterface(val))
  153. }
  154. return transformed
  155. }
  156. func transformMap(i map[interface{}]interface{}) interface{} {
  157. transformed := make(map[interface{}]interface{})
  158. for key, val := range i {
  159. transformed[key] = tranformInterface(val)
  160. }
  161. return transformed
  162. }
  163. // interpolateValue returns final value after interpolation. At the moment only env var interpolation is done
  164. // here but in the future something like interpolation from file could be also done here.
  165. // For a literal '$', '$$' can be used to avoid interpolation.
  166. func interpolateValue(val string) string {
  167. parts := strings.Split(val, "$$")
  168. interpolated := make([]string, len(parts))
  169. for i, v := range parts {
  170. interpolated[i] = os.ExpandEnv(v)
  171. }
  172. return strings.Join(interpolated, "$")
  173. }
  174. type interpolated struct {
  175. value string
  176. raw string
  177. }
  178. // getInterpolated unmarshals the value as string and runs interpolation on it. It is the responsibility of each
  179. // value type to convert this string value to appropriate type.
  180. func getInterpolated(unmarshal func(interface{}) error) (*interpolated, error) {
  181. var raw string
  182. err := unmarshal(&raw)
  183. if err != nil {
  184. return &interpolated{}, err
  185. }
  186. value := interpolateValue(raw)
  187. return &interpolated{raw: raw, value: value}, nil
  188. }