env.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. package v2
  2. import (
  3. "fmt"
  4. porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1"
  5. )
  6. // Env is a list of env variable definitions
  7. type Env []EnvVariableDefinition
  8. // EnvVariableSource indicates how to set an env variable
  9. type EnvVariableSource string
  10. const (
  11. // EnvVariableSource_Value indicates that the env variable should be set to an explicitly provided value
  12. EnvVariableSource_Value EnvVariableSource = "value"
  13. // EnvVariableSource_FromApp indicates that the env variable should be set to a value from another app
  14. EnvVariableSource_FromApp EnvVariableSource = "app"
  15. )
  16. // EnvVariableDefinition is a struct containing information about how to set an env variable
  17. type EnvVariableDefinition struct {
  18. Key string
  19. Source EnvVariableSource
  20. Value EnvValueOptional
  21. FromApp EnvVariableFromAppOptional
  22. }
  23. // EnvValueOptional is a struct wrapping an optional string value to be set as an env variable
  24. type EnvValueOptional struct {
  25. // Value is the actual value of the env variable
  26. Value string
  27. IsSet bool
  28. }
  29. // EnvValueFromApp indicates which value to pull from the app
  30. type EnvValueFromApp string
  31. const (
  32. // EnvValueFromApp_InternalDomain indicates that the internal domain should be pulled from the app
  33. EnvValueFromApp_InternalDomain EnvValueFromApp = "internal_domain"
  34. // EnvValueFromApp_PublicDomain indicates that the first found public domain should be pulled from the app
  35. EnvValueFromApp_PublicDomain EnvValueFromApp = "public_domain"
  36. )
  37. // EnvVariableFromApp is a struct containing information about how to set an env variable from another app
  38. type EnvVariableFromApp struct {
  39. // AppName is the name of the app to pull the value from
  40. AppName string
  41. // Value indicates which value to pull from the app
  42. Value EnvValueFromApp
  43. // ServiceName is the name of the service to pull the value from, if applicable
  44. ServiceName string
  45. }
  46. // EnvVariableFromAppOptional is an optional value indicating how to resolve an env variable from another app
  47. type EnvVariableFromAppOptional struct {
  48. Value EnvVariableFromApp
  49. IsSet bool
  50. }
  51. // UnmarshalYAML implements the yaml.Unmarshaler interface for Env in order to support both a list of env variables and a map of env variables
  52. func (e *Env) UnmarshalYAML(unmarshal func(interface{}) error) error {
  53. var asList []EnvVariableDefinition
  54. if err := unmarshal(&asList); err == nil {
  55. *e = asList
  56. return nil
  57. }
  58. var asMap map[string]string
  59. if err := unmarshal(&asMap); err != nil {
  60. return err
  61. }
  62. for key, value := range asMap {
  63. *e = append(*e, EnvVariableDefinition{
  64. Key: key,
  65. Source: EnvVariableSource_Value,
  66. Value: EnvValueOptional{
  67. Value: value,
  68. IsSet: true,
  69. },
  70. })
  71. }
  72. return nil
  73. }
  74. // MarshalYAML implements the yaml.Marshaler interface for Env in order to convert from the internal representation to the yaml representation
  75. func (e Env) MarshalYAML() (interface{}, error) {
  76. var rawList []rawEnvVarDef
  77. for _, def := range e {
  78. switch def.Source {
  79. case EnvVariableSource_Value:
  80. rawList = append(rawList, rawEnvVarDef{
  81. Key: def.Key,
  82. Value: def.Value.Value,
  83. })
  84. case EnvVariableSource_FromApp:
  85. rawList = append(rawList, rawEnvVarDef{
  86. Key: def.Key,
  87. From: rawEnvVariableReference{
  88. Source: EnvVariableSource_FromApp,
  89. Name: def.FromApp.Value.AppName,
  90. Value: string(def.FromApp.Value.Value),
  91. ServiceName: def.FromApp.Value.ServiceName,
  92. },
  93. })
  94. }
  95. }
  96. return rawList, nil
  97. }
  98. // rawEnvVarDef is a struct used to unmarshal the yaml representation of an env variable
  99. // this represents the structure of an env variable in the yaml file
  100. type rawEnvVarDef struct {
  101. Key string `yaml:"key"`
  102. Value string `yaml:"value,omitempty"`
  103. From rawEnvVariableReference `yaml:"from,omitempty"`
  104. }
  105. // rawEnvVariableReference is a struct used to unmarshal the yaml representation of an env variable reference
  106. type rawEnvVariableReference struct {
  107. // source for the value. right now only "app" is supported
  108. Source EnvVariableSource `yaml:"source,omitempty"`
  109. // name of the app to get the value from
  110. Name string `yaml:"name,omitempty"`
  111. // value to pull from the app, right now only public_domain or internal_domain are supported
  112. Value string `yaml:"value,omitempty"`
  113. // name of the source to get the value from. only set if source is "app"
  114. ServiceName string `yaml:"service,omitempty"`
  115. }
  116. // UnmarshalYAML implements the yaml.Unmarshaler interface for EnvVariableDefinition in order to support both a string value and a reference to another app
  117. func (def *EnvVariableDefinition) UnmarshalYAML(unmarshal func(interface{}) error) error {
  118. var raw rawEnvVarDef
  119. if err := unmarshal(&raw); err != nil {
  120. return err
  121. }
  122. def.Key = raw.Key
  123. if raw.Value != "" {
  124. def.Source = EnvVariableSource_Value
  125. def.Value = EnvValueOptional{
  126. Value: raw.Value,
  127. IsSet: true,
  128. }
  129. }
  130. if !def.Value.IsSet {
  131. switch raw.From.Source {
  132. case EnvVariableSource_FromApp:
  133. def.Source = EnvVariableSource_FromApp
  134. value, err := fromAppValue(raw.From.Value)
  135. if err != nil {
  136. return fmt.Errorf("unknown app value provided: %w", err)
  137. }
  138. def.FromApp = EnvVariableFromAppOptional{
  139. Value: EnvVariableFromApp{
  140. AppName: raw.From.Name,
  141. Value: value,
  142. ServiceName: raw.From.ServiceName,
  143. },
  144. IsSet: true,
  145. }
  146. default:
  147. return fmt.Errorf("invalid source %s for env variable", raw.From.Source)
  148. }
  149. }
  150. return nil
  151. }
  152. // EnvVarFromAppToProto converts an env variable from app to the proto representation
  153. func EnvVarFromAppToProto(value EnvVariableFromApp) (*porterv1.EnvVariableFromApp, error) {
  154. variable := &porterv1.EnvVariableFromApp{
  155. AppName: value.AppName,
  156. ServiceName: value.ServiceName,
  157. }
  158. switch value.Value {
  159. case EnvValueFromApp_InternalDomain:
  160. variable.Value = porterv1.EnvValueFromApp_ENV_VALUE_FROM_APP_INTERNAL_DOMAIN
  161. case EnvValueFromApp_PublicDomain:
  162. variable.Value = porterv1.EnvValueFromApp_ENV_VALUE_FROM_APP_PUBLIC_DOMAIN
  163. default:
  164. return nil, fmt.Errorf("invalid value %s for env variable from app", value.Value)
  165. }
  166. return variable, nil
  167. }
  168. // EnvVarFromAppFromProto converts a proto env variable from app to the internal representation
  169. func EnvVarFromAppFromProto(value *porterv1.EnvVariableFromApp) (EnvVariableFromAppOptional, error) {
  170. variable := EnvVariableFromAppOptional{
  171. Value: EnvVariableFromApp{
  172. AppName: value.AppName,
  173. ServiceName: value.ServiceName,
  174. },
  175. IsSet: true,
  176. }
  177. switch value.Value {
  178. case porterv1.EnvValueFromApp_ENV_VALUE_FROM_APP_INTERNAL_DOMAIN:
  179. variable.Value.Value = EnvValueFromApp_InternalDomain
  180. case porterv1.EnvValueFromApp_ENV_VALUE_FROM_APP_PUBLIC_DOMAIN:
  181. variable.Value.Value = EnvValueFromApp_PublicDomain
  182. default:
  183. return variable, fmt.Errorf("invalid value %s for env variable from app", value.Value)
  184. }
  185. return variable, nil
  186. }
  187. func fromAppValue(raw string) (EnvValueFromApp, error) {
  188. switch raw {
  189. case string(EnvValueFromApp_InternalDomain):
  190. return EnvValueFromApp_InternalDomain, nil
  191. case string(EnvValueFromApp_PublicDomain):
  192. return EnvValueFromApp_PublicDomain, nil
  193. default:
  194. return "", fmt.Errorf("invalid value %s for env variable from app", raw)
  195. }
  196. }