// ResourceLocation returns a URL to which one can send traffic for the specified service. func (rs *REST) ResourceLocation(ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { // Allow ID as "svcname" or "svcname:port". svcName, portStr, valid := util.SplitPort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid service request %q", id)) } eps, err := rs.endpoints.GetEndpoints(ctx, svcName) if err != nil { return nil, nil, err } if len(eps.Subsets) == 0 { return nil, nil, errors.NewServiceUnavailable(fmt.Sprintf("no endpoints available for service %q", svcName)) } // Pick a random Subset to start searching from. ssSeed := rand.Intn(len(eps.Subsets)) // Find a Subset that has the port. for ssi := 0; ssi < len(eps.Subsets); ssi++ { ss := &eps.Subsets[(ssSeed+ssi)%len(eps.Subsets)] for i := range ss.Ports { if ss.Ports[i].Name == portStr { // Pick a random address. ip := ss.Addresses[rand.Intn(len(ss.Addresses))].IP port := ss.Ports[i].Port // We leave off the scheme ('http://') because we have no idea what sort of server // is listening at this endpoint. return &url.URL{ Host: net.JoinHostPort(ip, strconv.Itoa(port)), }, nil, nil } } } return nil, nil, errors.NewServiceUnavailable(fmt.Sprintf("no endpoints available for service %q", id)) }
// ResourceLocation returns a URL to which one can send traffic for the specified service. func (rs *REST) ResourceLocation(ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { // Allow ID as "svcname", "svcname:port", or "scheme:svcname:port". svcScheme, svcName, portStr, valid := util.SplitSchemeNamePort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid service request %q", id)) } // If a port *number* was specified, find the corresponding service port name if portNum, err := strconv.ParseInt(portStr, 10, 64); err == nil { svc, err := rs.registry.GetService(ctx, svcName) if err != nil { return nil, nil, err } found := false for _, svcPort := range svc.Spec.Ports { if svcPort.Port == int(portNum) { // use the declared port's name portStr = svcPort.Name found = true break } } if !found { return nil, nil, errors.NewServiceUnavailable(fmt.Sprintf("no service port %d found for service %q", portNum, svcName)) } } eps, err := rs.endpoints.GetEndpoints(ctx, svcName) if err != nil { return nil, nil, err } if len(eps.Subsets) == 0 { return nil, nil, errors.NewServiceUnavailable(fmt.Sprintf("no endpoints available for service %q", svcName)) } // Pick a random Subset to start searching from. ssSeed := rand.Intn(len(eps.Subsets)) // Find a Subset that has the port. for ssi := 0; ssi < len(eps.Subsets); ssi++ { ss := &eps.Subsets[(ssSeed+ssi)%len(eps.Subsets)] if len(ss.Addresses) == 0 { continue } for i := range ss.Ports { if ss.Ports[i].Name == portStr { // Pick a random address. ip := ss.Addresses[rand.Intn(len(ss.Addresses))].IP port := ss.Ports[i].Port return &url.URL{ Scheme: svcScheme, Host: net.JoinHostPort(ip, strconv.Itoa(port)), }, rs.proxyTransport, nil } } } return nil, nil, errors.NewServiceUnavailable(fmt.Sprintf("no endpoints available for service %q", id)) }
// TestCreateRetryUnrecoverable ensures that an attempt to create a mapping // using failing registry update calls will return an error. func TestCreateRetryUnrecoverable(t *testing.T) { rest := &REST{ strategy: NewStrategy(testDefaultRegistry), imageRegistry: &fakeImageRegistry{ createImage: func(ctx kapi.Context, image *api.Image) error { return nil }, }, imageStreamRegistry: &fakeImageStreamRegistry{ getImageStream: func(ctx kapi.Context, id string) (*api.ImageStream, error) { return validImageStream(), nil }, listImageStreams: func(ctx kapi.Context, options *kapi.ListOptions) (*api.ImageStreamList, error) { s := validImageStream() return &api.ImageStreamList{Items: []api.ImageStream{*s}}, nil }, updateImageStreamStatus: func(ctx kapi.Context, repo *api.ImageStream) (*api.ImageStream, error) { return nil, errors.NewServiceUnavailable("unrecoverable error") }, }, } obj, err := rest.Create(kapi.NewDefaultContext(), validNewMappingWithName()) if err == nil { t.Errorf("expected an error") } if obj != nil { t.Fatalf("expected a nil result") } }
// ResourceLocation returns a URL to which one can send traffic for the specified service. func (rs *REST) ResourceLocation(ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { // Allow ID as "svcname", "svcname:port", or "scheme:svcname:port". svcScheme, svcName, portStr, valid := util.SplitSchemeNamePort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid service request %q", id)) } eps, err := rs.endpoints.GetEndpoints(ctx, svcName) if err != nil { return nil, nil, err } if len(eps.Subsets) == 0 { return nil, nil, errors.NewServiceUnavailable(fmt.Sprintf("no endpoints available for service %q", svcName)) } // Pick a random Subset to start searching from. ssSeed := rand.Intn(len(eps.Subsets)) // Find a Subset that has the port. for ssi := 0; ssi < len(eps.Subsets); ssi++ { ss := &eps.Subsets[(ssSeed+ssi)%len(eps.Subsets)] if len(ss.Addresses) == 0 { continue } for i := range ss.Ports { if ss.Ports[i].Name == portStr { // Pick a random address. ip := ss.Addresses[rand.Intn(len(ss.Addresses))].IP port := ss.Ports[i].Port return &url.URL{ Scheme: svcScheme, Host: net.JoinHostPort(ip, strconv.Itoa(port)), }, rs.proxyTransport, nil } else { port, err := strconv.ParseInt(portStr, 10, 64) if err == nil && int(port) == ss.Ports[i].Port { ip := ss.Addresses[rand.Intn(len(ss.Addresses))].IP return &url.URL{ Scheme: svcScheme, Host: net.JoinHostPort(ip, portStr), }, rs.proxyTransport, nil } } } } return nil, nil, errors.NewServiceUnavailable(fmt.Sprintf("no endpoints available for service %q", id)) }