envvars.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package envvars
  14. import (
  15. "fmt"
  16. "net"
  17. "strconv"
  18. "strings"
  19. "k8s.io/api/core/v1"
  20. v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
  21. )
  22. // FromServices builds environment variables that a container is started with,
  23. // which tell the container where to find the services it may need, which are
  24. // provided as an argument.
  25. func FromServices(services []*v1.Service) []v1.EnvVar {
  26. var result []v1.EnvVar
  27. for i := range services {
  28. service := services[i]
  29. // ignore services where ClusterIP is "None" or empty
  30. // the services passed to this method should be pre-filtered
  31. // only services that have the cluster IP set should be included here
  32. if !v1helper.IsServiceIPSet(service) {
  33. continue
  34. }
  35. // Host
  36. name := makeEnvVariableName(service.Name) + "_SERVICE_HOST"
  37. result = append(result, v1.EnvVar{Name: name, Value: service.Spec.ClusterIP})
  38. // First port - give it the backwards-compatible name
  39. name = makeEnvVariableName(service.Name) + "_SERVICE_PORT"
  40. result = append(result, v1.EnvVar{Name: name, Value: strconv.Itoa(int(service.Spec.Ports[0].Port))})
  41. // All named ports (only the first may be unnamed, checked in validation)
  42. for i := range service.Spec.Ports {
  43. sp := &service.Spec.Ports[i]
  44. if sp.Name != "" {
  45. pn := name + "_" + makeEnvVariableName(sp.Name)
  46. result = append(result, v1.EnvVar{Name: pn, Value: strconv.Itoa(int(sp.Port))})
  47. }
  48. }
  49. // Docker-compatible vars.
  50. result = append(result, makeLinkVariables(service)...)
  51. }
  52. return result
  53. }
  54. func makeEnvVariableName(str string) string {
  55. // TODO: If we simplify to "all names are DNS1123Subdomains" this
  56. // will need two tweaks:
  57. // 1) Handle leading digits
  58. // 2) Handle dots
  59. return strings.ToUpper(strings.Replace(str, "-", "_", -1))
  60. }
  61. func makeLinkVariables(service *v1.Service) []v1.EnvVar {
  62. prefix := makeEnvVariableName(service.Name)
  63. all := []v1.EnvVar{}
  64. for i := range service.Spec.Ports {
  65. sp := &service.Spec.Ports[i]
  66. protocol := string(v1.ProtocolTCP)
  67. if sp.Protocol != "" {
  68. protocol = string(sp.Protocol)
  69. }
  70. hostPort := net.JoinHostPort(service.Spec.ClusterIP, strconv.Itoa(int(sp.Port)))
  71. if i == 0 {
  72. // Docker special-cases the first port.
  73. all = append(all, v1.EnvVar{
  74. Name: prefix + "_PORT",
  75. Value: fmt.Sprintf("%s://%s", strings.ToLower(protocol), hostPort),
  76. })
  77. }
  78. portPrefix := fmt.Sprintf("%s_PORT_%d_%s", prefix, sp.Port, strings.ToUpper(protocol))
  79. all = append(all, []v1.EnvVar{
  80. {
  81. Name: portPrefix,
  82. Value: fmt.Sprintf("%s://%s", strings.ToLower(protocol), hostPort),
  83. },
  84. {
  85. Name: portPrefix + "_PROTO",
  86. Value: strings.ToLower(protocol),
  87. },
  88. {
  89. Name: portPrefix + "_PORT",
  90. Value: strconv.Itoa(int(sp.Port)),
  91. },
  92. {
  93. Name: portPrefix + "_ADDR",
  94. Value: service.Spec.ClusterIP,
  95. },
  96. }...)
  97. }
  98. return all
  99. }