values.go 5.1 KB

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