// 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 pod. func ResourceLocation(getter ResourceGetter, ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { // Allow ID as "podname" or "podname:port". If port is not specified, // try to use the first defined port on the pod. name, port, valid := util.SplitPort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid pod request %q", id)) } // TODO: if port is not a number but a "(container)/(portname)", do a name lookup. pod, err := getPod(getter, ctx, name) if err != nil { return nil, nil, err } // Try to figure out a port. if port == "" { for i := range pod.Spec.Containers { if len(pod.Spec.Containers[i].Ports) > 0 { port = fmt.Sprintf("%d", pod.Spec.Containers[i].Ports[0].ContainerPort) break } } } // We leave off the scheme ('http://') because we have no idea what sort of server // is listening at this endpoint. loc := &url.URL{} if port == "" { loc.Host = pod.Status.PodIP } else { loc.Host = net.JoinHostPort(pod.Status.PodIP, port) } return loc, nil, nil }
// ResourceLocation returns an URL and transport which one can use to send traffic for the specified node. func ResourceLocation(getter ResourceGetter, connection client.ConnectionInfoGetter, ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { name, portReq, valid := util.SplitPort(id) if !valid { return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid node request %q", id)) } nodeObj, err := getter.Get(ctx, name) if err != nil { return nil, nil, err } node := nodeObj.(*api.Node) hostIP, err := nodeutil.GetNodeHostIP(node) if err != nil { return nil, nil, err } host := hostIP.String() if portReq == "" || strconv.Itoa(ports.KubeletPort) == portReq { scheme, port, transport, err := connection.GetConnectionInfo(host) if err != nil { return nil, nil, err } return &url.URL{ Scheme: scheme, Host: net.JoinHostPort( host, strconv.FormatUint(uint64(port), 10), ), }, transport, nil } return &url.URL{Host: net.JoinHostPort(host, portReq)}, nil, nil }