serviceloadbalancers.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. Copyright 2015 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 e2e
  14. import (
  15. "fmt"
  16. "io/ioutil"
  17. "net/http"
  18. "k8s.io/kubernetes/pkg/api"
  19. client "k8s.io/kubernetes/pkg/client/unversioned"
  20. "k8s.io/kubernetes/pkg/labels"
  21. "k8s.io/kubernetes/pkg/runtime"
  22. "k8s.io/kubernetes/pkg/util/wait"
  23. utilyaml "k8s.io/kubernetes/pkg/util/yaml"
  24. "k8s.io/kubernetes/test/e2e/framework"
  25. . "github.com/onsi/ginkgo"
  26. . "github.com/onsi/gomega"
  27. )
  28. // getLoadBalancerControllers returns a list of LBCtesters.
  29. func getLoadBalancerControllers(client *client.Client) []LBCTester {
  30. return []LBCTester{
  31. &haproxyControllerTester{
  32. name: "haproxy",
  33. cfg: "test/e2e/testing-manifests/serviceloadbalancer/haproxyrc.yaml",
  34. client: client,
  35. },
  36. }
  37. }
  38. // getIngManagers returns a list of ingManagers.
  39. func getIngManagers(client *client.Client) []*ingManager {
  40. return []*ingManager{
  41. {
  42. name: "netexec",
  43. rcCfgPaths: []string{"test/e2e/testing-manifests/serviceloadbalancer/netexecrc.yaml"},
  44. svcCfgPaths: []string{"test/e2e/testing-manifests/serviceloadbalancer/netexecsvc.yaml"},
  45. svcNames: []string{},
  46. client: client,
  47. },
  48. }
  49. }
  50. // LBCTester is an interface used to test loadbalancer controllers.
  51. type LBCTester interface {
  52. // start starts the loadbalancer controller in the given namespace
  53. start(namespace string) error
  54. // lookup returns the address (ip/hostname) associated with ingressKey
  55. lookup(ingressKey string) string
  56. // stop stops the loadbalancer controller
  57. stop() error
  58. // name returns the name of the loadbalancer
  59. getName() string
  60. }
  61. // haproxyControllerTester implements LBCTester for bare metal haproxy LBs.
  62. type haproxyControllerTester struct {
  63. client *client.Client
  64. cfg string
  65. rcName string
  66. rcNamespace string
  67. name string
  68. address []string
  69. }
  70. func (h *haproxyControllerTester) getName() string {
  71. return h.name
  72. }
  73. func (h *haproxyControllerTester) start(namespace string) (err error) {
  74. // Create a replication controller with the given configuration.
  75. rc := rcFromManifest(h.cfg)
  76. rc.Namespace = namespace
  77. rc.Spec.Template.Labels["name"] = rc.Name
  78. // Add the --namespace arg.
  79. // TODO: Remove this when we have proper namespace support.
  80. for i, c := range rc.Spec.Template.Spec.Containers {
  81. rc.Spec.Template.Spec.Containers[i].Args = append(
  82. c.Args, fmt.Sprintf("--namespace=%v", namespace))
  83. framework.Logf("Container args %+v", rc.Spec.Template.Spec.Containers[i].Args)
  84. }
  85. rc, err = h.client.ReplicationControllers(rc.Namespace).Create(rc)
  86. if err != nil {
  87. return
  88. }
  89. if err = framework.WaitForRCPodsRunning(h.client, namespace, rc.Name); err != nil {
  90. return
  91. }
  92. h.rcName = rc.Name
  93. h.rcNamespace = rc.Namespace
  94. // Find the pods of the rc we just created.
  95. labelSelector := labels.SelectorFromSet(
  96. labels.Set(map[string]string{"name": h.rcName}))
  97. options := api.ListOptions{LabelSelector: labelSelector}
  98. pods, err := h.client.Pods(h.rcNamespace).List(options)
  99. if err != nil {
  100. return err
  101. }
  102. // Find the external addresses of the nodes the pods are running on.
  103. for _, p := range pods.Items {
  104. wait.Poll(pollInterval, framework.ServiceRespondingTimeout, func() (bool, error) {
  105. address, err := framework.GetHostExternalAddress(h.client, &p)
  106. if err != nil {
  107. framework.Logf("%v", err)
  108. return false, nil
  109. }
  110. h.address = append(h.address, address)
  111. return true, nil
  112. })
  113. }
  114. if len(h.address) == 0 {
  115. return fmt.Errorf("No external ips found for loadbalancer %v", h.getName())
  116. }
  117. return nil
  118. }
  119. func (h *haproxyControllerTester) stop() error {
  120. return h.client.ReplicationControllers(h.rcNamespace).Delete(h.rcName, nil)
  121. }
  122. func (h *haproxyControllerTester) lookup(ingressKey string) string {
  123. // The address of a service is the address of the lb/servicename, currently.
  124. return fmt.Sprintf("http://%v/%v", h.address[0], ingressKey)
  125. }
  126. // ingManager starts an rc and the associated service.
  127. type ingManager struct {
  128. rcCfgPaths []string
  129. svcCfgPaths []string
  130. ingCfgPath string
  131. name string
  132. namespace string
  133. client *client.Client
  134. svcNames []string
  135. }
  136. func (s *ingManager) getName() string {
  137. return s.name
  138. }
  139. func (s *ingManager) start(namespace string) (err error) {
  140. // Create rcs
  141. for _, rcPath := range s.rcCfgPaths {
  142. rc := rcFromManifest(rcPath)
  143. rc.Namespace = namespace
  144. rc.Spec.Template.Labels["name"] = rc.Name
  145. rc, err = s.client.ReplicationControllers(rc.Namespace).Create(rc)
  146. if err != nil {
  147. return
  148. }
  149. if err = framework.WaitForRCPodsRunning(s.client, rc.Namespace, rc.Name); err != nil {
  150. return
  151. }
  152. }
  153. // Create services.
  154. // Note that it's up to the caller to make sure the service actually matches
  155. // the pods of the rc.
  156. for _, svcPath := range s.svcCfgPaths {
  157. svc := svcFromManifest(svcPath)
  158. svc.Namespace = namespace
  159. svc, err = s.client.Services(svc.Namespace).Create(svc)
  160. if err != nil {
  161. return
  162. }
  163. // TODO: This is short term till we have an Ingress.
  164. s.svcNames = append(s.svcNames, svc.Name)
  165. }
  166. s.name = s.svcNames[0]
  167. s.namespace = namespace
  168. return nil
  169. }
  170. func (s *ingManager) test(path string) error {
  171. url := fmt.Sprintf("%v/hostName", path)
  172. httpClient := &http.Client{}
  173. return wait.Poll(pollInterval, framework.ServiceRespondingTimeout, func() (bool, error) {
  174. body, err := simpleGET(httpClient, url, "")
  175. if err != nil {
  176. framework.Logf("%v\n%v\n%v", url, body, err)
  177. return false, nil
  178. }
  179. return true, nil
  180. })
  181. }
  182. var _ = framework.KubeDescribe("ServiceLoadBalancer [Feature:ServiceLoadBalancer]", func() {
  183. // These variables are initialized after framework's beforeEach.
  184. var ns string
  185. var client *client.Client
  186. f := framework.NewDefaultFramework("servicelb")
  187. BeforeEach(func() {
  188. client = f.Client
  189. ns = f.Namespace.Name
  190. })
  191. It("should support simple GET on Ingress ips", func() {
  192. for _, t := range getLoadBalancerControllers(client) {
  193. By(fmt.Sprintf("Starting loadbalancer controller %v in namespace %v", t.getName(), ns))
  194. Expect(t.start(ns)).NotTo(HaveOccurred())
  195. for _, s := range getIngManagers(client) {
  196. By(fmt.Sprintf("Starting ingress manager %v in namespace %v", s.getName(), ns))
  197. Expect(s.start(ns)).NotTo(HaveOccurred())
  198. for _, sName := range s.svcNames {
  199. path := t.lookup(sName)
  200. framework.Logf("Testing path %v", path)
  201. Expect(s.test(path)).NotTo(HaveOccurred())
  202. }
  203. }
  204. Expect(t.stop()).NotTo(HaveOccurred())
  205. }
  206. })
  207. })
  208. // simpleGET executes a get on the given url, returns error if non-200 returned.
  209. func simpleGET(c *http.Client, url, host string) (string, error) {
  210. req, err := http.NewRequest("GET", url, nil)
  211. if err != nil {
  212. return "", err
  213. }
  214. req.Host = host
  215. res, err := c.Do(req)
  216. if err != nil {
  217. return "", err
  218. }
  219. defer res.Body.Close()
  220. rawBody, err := ioutil.ReadAll(res.Body)
  221. if err != nil {
  222. return "", err
  223. }
  224. body := string(rawBody)
  225. if res.StatusCode != http.StatusOK {
  226. err = fmt.Errorf(
  227. "GET returned http error %v", res.StatusCode)
  228. }
  229. return body, err
  230. }
  231. // rcFromManifest reads a .json/yaml file and returns the rc in it.
  232. func rcFromManifest(fileName string) *api.ReplicationController {
  233. var controller api.ReplicationController
  234. framework.Logf("Parsing rc from %v", fileName)
  235. data := framework.ReadOrDie(fileName)
  236. json, err := utilyaml.ToJSON(data)
  237. Expect(err).NotTo(HaveOccurred())
  238. Expect(runtime.DecodeInto(api.Codecs.UniversalDecoder(), json, &controller)).NotTo(HaveOccurred())
  239. return &controller
  240. }
  241. // svcFromManifest reads a .json/yaml file and returns the rc in it.
  242. func svcFromManifest(fileName string) *api.Service {
  243. var svc api.Service
  244. framework.Logf("Parsing service from %v", fileName)
  245. data := framework.ReadOrDie(fileName)
  246. json, err := utilyaml.ToJSON(data)
  247. Expect(err).NotTo(HaveOccurred())
  248. Expect(runtime.DecodeInto(api.Codecs.UniversalDecoder(), json, &svc)).NotTo(HaveOccurred())
  249. return &svc
  250. }