func createRoutesForDomain(ns string, domain string, c *k8sclient.Client, oc *oclient.Client, fac *cmdutil.Factory) error { rc, err := c.Services(ns).List(labels.Everything()) if err != nil { util.Errorf("Failed to load services in namespace %s with error %v", ns, err) return err } items := rc.Items for _, service := range items { // TODO use the external load balancer as a way to know if we should create a route? name := service.ObjectMeta.Name if name != "kubernetes" { routes := oc.Routes(ns) _, err = routes.Get(name) if err != nil { hostName := name + "." + domain route := rapi.Route{ ObjectMeta: kapi.ObjectMeta{ Name: name, }, Host: hostName, ServiceName: name, } // lets create the route _, err = routes.Create(&route) if err != nil { util.Errorf("Failed to create the route %s with error %v", name, err) return err } } } } return nil }
// Creates a replication controller that serves its hostname and a service on top of it. func startServeHostnameService(c *client.Client, ns, name string, port, replicas int) ([]string, string, error) { podNames := make([]string, replicas) _, err := c.Services(ns).Create(&api.Service{ ObjectMeta: api.ObjectMeta{ Name: name, }, Spec: api.ServiceSpec{ Ports: []api.ServicePort{{ Port: port, TargetPort: util.NewIntOrStringFromInt(9376), Protocol: "TCP", }}, Selector: map[string]string{ "name": name, }, }, }) if err != nil { return podNames, "", err } var createdPods []*api.Pod maxContainerFailures := 0 config := RCConfig{ Client: c, Image: "gcr.io/google_containers/serve_hostname:1.1", Name: name, Namespace: ns, PollInterval: 3 * time.Second, Timeout: 30 * time.Second, Replicas: replicas, CreatedPods: &createdPods, MaxContainerFailures: &maxContainerFailures, } err = RunRC(config) if err != nil { return podNames, "", err } if len(createdPods) != replicas { return podNames, "", fmt.Errorf("Incorrect number of running pods: %v", len(createdPods)) } for i := range createdPods { podNames[i] = createdPods[i].ObjectMeta.Name } sort.StringSlice(podNames).Sort() service, err := c.Services(ns).Get(name) if err != nil { return podNames, "", err } if service.Spec.ClusterIP == "" { return podNames, "", fmt.Errorf("Service IP is blank for %v", name) } serviceIP := service.Spec.ClusterIP return podNames, serviceIP, nil }
func stopServeHostnameService(c *client.Client, ns, name string) error { if err := DeleteRC(c, ns, name); err != nil { return err } if err := c.Services(ns).Delete(name); err != nil { return err } return nil }
func validateTemplateService(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) { ns, _, err := f.DefaultNamespace() if err != nil { return Failure, err } svc, err := c.Services(ns).Get("templates") if svc != nil { return Success, err } return Failure, err }
func runMasterServiceTest(client *client.Client) { time.Sleep(12 * time.Second) svcList, err := client.Services(api.NamespaceDefault).List(labels.Everything()) if err != nil { glog.Fatalf("unexpected error listing services: %v", err) } var foundRW bool found := util.StringSet{} for i := range svcList.Items { found.Insert(svcList.Items[i].Name) if svcList.Items[i].Name == "kubernetes" { foundRW = true } } if foundRW { ep, err := client.Endpoints(api.NamespaceDefault).Get("kubernetes") if err != nil { glog.Fatalf("unexpected error listing endpoints for kubernetes service: %v", err) } if countEndpoints(ep) == 0 { glog.Fatalf("no endpoints for kubernetes service: %v", ep) } } else { glog.Errorf("no RW service found: %v", found) glog.Fatal("Kubernetes service test failed") } glog.Infof("Master service test passed.") }
func expectedServicesExist(c *client.Client) error { serviceList, err := c.Services(api.NamespaceSystem).List(labels.Everything()) if err != nil { return err } for _, service := range serviceList.Items { if _, ok := expectedServices[service.Name]; ok { expectedServices[service.Name] = true } } for service, found := range expectedServices { if !found { return fmt.Errorf("Service %q not found", service) } } return nil }
func waitForLoadBalancerDestroy(c *client.Client, serviceName, namespace string) (*api.Service, error) { // TODO: once support ticket 21807001 is resolved, reduce this timeout back to something reasonable const timeout = 10 * time.Minute var service *api.Service By(fmt.Sprintf("waiting up to %v for service %s in namespace %s to have no LoadBalancer ingress points", timeout, serviceName, namespace)) for start := time.Now(); time.Since(start) < timeout; time.Sleep(5 * time.Second) { service, err := c.Services(namespace).Get(serviceName) if err != nil { Logf("Get service failed, ignoring for 5s: %v", err) continue } if len(service.Status.LoadBalancer.Ingress) == 0 { return service, nil } Logf("Waiting for service %s in namespace %s to have no LoadBalancer ingress points (%v)", serviceName, namespace, time.Since(start)) } return service, fmt.Errorf("service %s in namespace %s still has LoadBalancer ingress points after %.2f seconds", serviceName, namespace, timeout.Seconds()) }
// updateService fetches a service, calls the update function on it, // and then attempts to send the updated service. It retries up to 2 // times in the face of timeouts and conflicts. func updateService(c *client.Client, namespace, serviceName string, update func(*api.Service)) (*api.Service, error) { var service *api.Service var err error for i := 0; i < 3; i++ { service, err = c.Services(namespace).Get(serviceName) if err != nil { return service, err } update(service) service, err = c.Services(namespace).Update(service) if !errors.IsConflict(err) && !errors.IsServerTimeout(err) { return service, err } } return service, err }
// Clean both server and client pods. func volumeTestCleanup(client *client.Client, config VolumeTestConfig) { By(fmt.Sprint("cleaning the environment after ", config.prefix)) defer GinkgoRecover() podClient := client.Pods(config.namespace) serviceClient := client.Services(config.namespace) // ignore all errors, the pods may not be even created podClient.Delete(config.prefix+"-client", nil) serviceClient.Delete(config.prefix + "-server") podClient.Delete(config.prefix+"-server", nil) }
func runSelfLinkTestOnNamespace(c *client.Client, namespace string) { svcBody := api.Service{ ObjectMeta: api.ObjectMeta{ Name: "selflinktest", Namespace: namespace, Labels: map[string]string{ "name": "selflinktest", }, }, Spec: api.ServiceSpec{ // This is here because validation requires it. Selector: map[string]string{ "foo": "bar", }, Ports: []api.ServicePort{{ Port: 12345, Protocol: "TCP", }}, SessionAffinity: "None", }, } services := c.Services(namespace) svc, err := services.Create(&svcBody) if err != nil { glog.Fatalf("Failed creating selflinktest service: %v", err) } err = c.Get().RequestURI(svc.SelfLink).Do().Into(svc) if err != nil { glog.Fatalf("Failed listing service with supplied self link '%v': %v", svc.SelfLink, err) } svcList, err := services.List(labels.Everything()) if err != nil { glog.Fatalf("Failed listing services: %v", err) } err = c.Get().RequestURI(svcList.SelfLink).Do().Into(svcList) if err != nil { glog.Fatalf("Failed listing services with supplied self link '%v': %v", svcList.SelfLink, err) } found := false for i := range svcList.Items { item := &svcList.Items[i] if item.Name != "selflinktest" { continue } found = true err = c.Get().RequestURI(item.SelfLink).Do().Into(svc) if err != nil { glog.Fatalf("Failed listing service with supplied self link '%v': %v", item.SelfLink, err) } break } if !found { glog.Fatalf("never found selflinktest service in namespace %s", namespace) } glog.Infof("Self link test passed in namespace %s", namespace) // TODO: Should test PUT at some point, too. }
func runPatchTest(c *client.Client) { name := "patchservice" resource := "services" svcBody := api.Service{ TypeMeta: api.TypeMeta{ APIVersion: c.APIVersion(), }, ObjectMeta: api.ObjectMeta{ Name: name, Labels: map[string]string{}, }, Spec: api.ServiceSpec{ // This is here because validation requires it. Selector: map[string]string{ "foo": "bar", }, Ports: []api.ServicePort{{ Port: 12345, Protocol: "TCP", }}, SessionAffinity: "None", }, } services := c.Services(api.NamespaceDefault) svc, err := services.Create(&svcBody) if err != nil { glog.Fatalf("Failed creating patchservice: %v", err) } patchBodies := map[string]map[api.PatchType]struct { AddLabelBody []byte RemoveLabelBody []byte RemoveAllLabelsBody []byte }{ "v1": { api.JSONPatchType: { []byte(`[{"op":"add","path":"/metadata/labels","value":{"foo":"bar","baz":"qux"}}]`), []byte(`[{"op":"remove","path":"/metadata/labels/foo"}]`), []byte(`[{"op":"remove","path":"/metadata/labels"}]`), }, api.MergePatchType: { []byte(`{"metadata":{"labels":{"foo":"bar","baz":"qux"}}}`), []byte(`{"metadata":{"labels":{"foo":null}}}`), []byte(`{"metadata":{"labels":null}}`), }, api.StrategicMergePatchType: { []byte(`{"metadata":{"labels":{"foo":"bar","baz":"qux"}}}`), []byte(`{"metadata":{"labels":{"foo":null}}}`), []byte(`{"metadata":{"labels":{"$patch":"replace"}}}`), }, }, } pb := patchBodies[c.APIVersion()] execPatch := func(pt api.PatchType, body []byte) error { return c.Patch(pt). Resource(resource). Namespace(api.NamespaceDefault). Name(name). Body(body). Do(). Error() } for k, v := range pb { // add label err := execPatch(k, v.AddLabelBody) if err != nil { glog.Fatalf("Failed updating patchservice with patch type %s: %v", k, err) } svc, err = services.Get(name) if err != nil { glog.Fatalf("Failed getting patchservice: %v", err) } if len(svc.Labels) != 2 || svc.Labels["foo"] != "bar" || svc.Labels["baz"] != "qux" { glog.Fatalf("Failed updating patchservice with patch type %s: labels are: %v", k, svc.Labels) } // remove one label err = execPatch(k, v.RemoveLabelBody) if err != nil { glog.Fatalf("Failed updating patchservice with patch type %s: %v", k, err) } svc, err = services.Get(name) if err != nil { glog.Fatalf("Failed getting patchservice: %v", err) } if len(svc.Labels) != 1 || svc.Labels["baz"] != "qux" { glog.Fatalf("Failed updating patchservice with patch type %s: labels are: %v", k, svc.Labels) } // remove all labels err = execPatch(k, v.RemoveAllLabelsBody) if err != nil { glog.Fatalf("Failed updating patchservice with patch type %s: %v", k, err) } svc, err = services.Get(name) if err != nil { glog.Fatalf("Failed getting patchservice: %v", err) } if svc.Labels != nil { glog.Fatalf("Failed remove all labels from patchservice with patch type %s: %v", k, svc.Labels) } } glog.Info("PATCHs work.") }
func runServiceTest(client *client.Client) { pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "foo", Labels: map[string]string{ "name": "thisisalonglabel", }, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "c1", Image: "foo", Ports: []api.ContainerPort{ {ContainerPort: 1234}, }, ImagePullPolicy: api.PullIfNotPresent, }, }, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, Status: api.PodStatus{ PodIP: "1.2.3.4", }, } pod, err := client.Pods(api.NamespaceDefault).Create(pod) if err != nil { glog.Fatalf("Failed to create pod: %v, %v", pod, err) } if err := wait.Poll(time.Second, time.Second*20, podExists(client, pod.Namespace, pod.Name)); err != nil { glog.Fatalf("FAILED: pod never started running %v", err) } svc1 := &api.Service{ ObjectMeta: api.ObjectMeta{Name: "service1"}, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "thisisalonglabel", }, Ports: []api.ServicePort{{ Port: 8080, Protocol: "TCP", }}, SessionAffinity: "None", }, } svc1, err = client.Services(api.NamespaceDefault).Create(svc1) if err != nil { glog.Fatalf("Failed to create service: %v, %v", svc1, err) } // create an identical service in the non-default namespace svc3 := &api.Service{ ObjectMeta: api.ObjectMeta{Name: "service1"}, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "thisisalonglabel", }, Ports: []api.ServicePort{{ Port: 8080, Protocol: "TCP", }}, SessionAffinity: "None", }, } svc3, err = client.Services("other").Create(svc3) if err != nil { glog.Fatalf("Failed to create service: %v, %v", svc3, err) } // TODO Reduce the timeouts in this test when endpoints controller is sped up. See #6045. if err := wait.Poll(time.Second, time.Second*60, endpointsSet(client, svc1.Namespace, svc1.Name, 1)); err != nil { glog.Fatalf("FAILED: unexpected endpoints: %v", err) } // A second service with the same port. svc2 := &api.Service{ ObjectMeta: api.ObjectMeta{Name: "service2"}, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "thisisalonglabel", }, Ports: []api.ServicePort{{ Port: 8080, Protocol: "TCP", }}, SessionAffinity: "None", }, } svc2, err = client.Services(api.NamespaceDefault).Create(svc2) if err != nil { glog.Fatalf("Failed to create service: %v, %v", svc2, err) } if err := wait.Poll(time.Second, time.Second*60, endpointsSet(client, svc2.Namespace, svc2.Name, 1)); err != nil { glog.Fatalf("FAILED: unexpected endpoints: %v", err) } if err := wait.Poll(time.Second, time.Second*60, endpointsSet(client, svc3.Namespace, svc3.Name, 0)); err != nil { glog.Fatalf("FAILED: service in other namespace should have no endpoints: %v", err) } svcList, err := client.Services(api.NamespaceAll).List(labels.Everything()) if err != nil { glog.Fatalf("Failed to list services across namespaces: %v", err) } names := util.NewStringSet() for _, svc := range svcList.Items { names.Insert(fmt.Sprintf("%s/%s", svc.Namespace, svc.Name)) } if !names.HasAll("default/kubernetes", "default/service1", "default/service2", "other/service1") { glog.Fatalf("Unexpected service list: %#v", names) } glog.Info("Service test passed.") }
Expect(err).NotTo(HaveOccurred()) namespaces[i] = namespacePtr.Name } }) AfterEach(func() { for _, ns := range namespaces { By(fmt.Sprintf("Destroying namespace %v", ns)) if err := c.Namespaces().Delete(ns); err != nil { Failf("Couldn't delete namespace %s: %s", ns, err) } } }) // TODO: We get coverage of TCP/UDP and multi-port services through the DNS test. We should have a simpler test for multi-port TCP here. It("should provide secure master service", func() { _, err := c.Services(api.NamespaceDefault).Get("kubernetes") Expect(err).NotTo(HaveOccurred()) }) It("should serve a basic endpoint from pods", func() { serviceName := "endpoint-test2" ns := namespaces[0] labels := map[string]string{ "foo": "bar", "baz": "blah", } defer func() { err := c.Services(ns).Delete(serviceName) Expect(err).NotTo(HaveOccurred()) }()
func newSVCByName(c *client.Client, ns, name string) error { _, err := c.Services(ns).Create(svcByName(name)) return err }
if len(ipToPort) != 1 { Logf("No IP found, retrying") continue } for _, port := range ipToPort { if port[0] != redisPort { Failf("Wrong endpoint port: %d", port[0]) } } endpointFound = true break } if !endpointFound { Failf("1 endpoint is expected") } service, err := c.Services(ns).Get(name) Expect(err).NotTo(HaveOccurred()) if len(service.Spec.Ports) != 1 { Failf("1 port is expected") } port := service.Spec.Ports[0] if port.Port != servicePort { Failf("Wrong service port: %d", port.Port) } if port.TargetPort.IntVal != redisPort { Failf("Wrong target port: %d") } } By("exposing RC")
func runAtomicPutTest(c *client.Client) { svcBody := api.Service{ TypeMeta: api.TypeMeta{ APIVersion: c.APIVersion(), }, ObjectMeta: api.ObjectMeta{ Name: "atomicservice", Labels: map[string]string{ "name": "atomicService", }, }, Spec: api.ServiceSpec{ // This is here because validation requires it. Selector: map[string]string{ "foo": "bar", }, Ports: []api.ServicePort{{ Port: 12345, Protocol: "TCP", }}, SessionAffinity: "None", }, } services := c.Services(api.NamespaceDefault) svc, err := services.Create(&svcBody) if err != nil { glog.Fatalf("Failed creating atomicService: %v", err) } glog.Info("Created atomicService") testLabels := labels.Set{ "foo": "bar", } for i := 0; i < 5; i++ { // a: z, b: y, etc... testLabels[string([]byte{byte('a' + i)})] = string([]byte{byte('z' - i)}) } var wg sync.WaitGroup wg.Add(len(testLabels)) for label, value := range testLabels { go func(l, v string) { for { glog.Infof("Starting to update (%s, %s)", l, v) tmpSvc, err := services.Get(svc.Name) if err != nil { glog.Errorf("Error getting atomicService: %v", err) continue } if tmpSvc.Spec.Selector == nil { tmpSvc.Spec.Selector = map[string]string{l: v} } else { tmpSvc.Spec.Selector[l] = v } glog.Infof("Posting update (%s, %s)", l, v) tmpSvc, err = services.Update(tmpSvc) if err != nil { if apierrors.IsConflict(err) { glog.Infof("Conflict: (%s, %s)", l, v) // This is what we expect. continue } glog.Errorf("Unexpected error putting atomicService: %v", err) continue } break } glog.Infof("Done update (%s, %s)", l, v) wg.Done() }(label, value) } wg.Wait() svc, err = services.Get(svc.Name) if err != nil { glog.Fatalf("Failed getting atomicService after writers are complete: %v", err) } if !reflect.DeepEqual(testLabels, labels.Set(svc.Spec.Selector)) { glog.Fatalf("Selector PUTs were not atomic: wanted %v, got %v", testLabels, svc.Spec.Selector) } glog.Info("Atomic PUTs work.") }
// Starts a container specified by config.serverImage and exports all // config.serverPorts from it via a service. The function returns IP // address of the service. func startVolumeServer(client *client.Client, config VolumeTestConfig) string { podClient := client.Pods(config.namespace) serviceClient := client.Services(config.namespace) portCount := len(config.serverPorts) serverPodPorts := make([]api.ContainerPort, portCount) servicePorts := make([]api.ServicePort, portCount) for i := 0; i < portCount; i++ { portName := fmt.Sprintf("%s-%d", config.prefix, i) serverPodPorts[i] = api.ContainerPort{ Name: portName, ContainerPort: config.serverPorts[i], Protocol: api.ProtocolTCP, } servicePorts[i] = api.ServicePort{ Name: portName, Protocol: "TCP", Port: config.serverPorts[i], TargetPort: util.NewIntOrStringFromInt(config.serverPorts[i]), } } By(fmt.Sprint("creating ", config.prefix, " server pod")) privileged := new(bool) *privileged = true serverPod := &api.Pod{ TypeMeta: api.TypeMeta{ Kind: "Pod", APIVersion: "v1", }, ObjectMeta: api.ObjectMeta{ Name: config.prefix + "-server", Labels: map[string]string{ "role": config.prefix + "-server", }, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: config.prefix + "-server", Image: config.serverImage, SecurityContext: &api.SecurityContext{ Privileged: privileged, }, Ports: serverPodPorts, }, }, }, } _, err := podClient.Create(serverPod) expectNoError(err, "Failed to create %s pod: %v", serverPod.Name, err) expectNoError(waitForPodRunningInNamespace(client, serverPod.Name, config.namespace)) By(fmt.Sprint("creating ", config.prefix, " service")) service := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: config.prefix + "-server", }, Spec: api.ServiceSpec{ Selector: map[string]string{ "role": config.prefix + "-server", }, Ports: servicePorts, }, } createdService, err := serviceClient.Create(service) expectNoError(err, "Failed to create %s service: %v", service.Name, err) By("sleeping a bit to give the server time to start") time.Sleep(20 * time.Second) ip := createdService.Spec.ClusterIP return ip }