// ResourceLocation returns a URL to which one can send traffic for the specified pod. func ResourceLocation(getter ResourceGetter, rt http.RoundTripper, ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { // Allow ID as "podname" or "podname:port" or "scheme:podname:port". // If port is not specified, try to use the first defined port on the pod. scheme, name, port, valid := util.SplitSchemeNamePort(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 } } } loc := &url.URL{ Scheme: scheme, } if port == "" { loc.Host = pod.Status.PodIP } else { loc.Host = net.JoinHostPort(pod.Status.PodIP, port) } return loc, rt, 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, proxyTransport http.RoundTripper, ctx api.Context, id string) (*url.URL, http.RoundTripper, error) { schemeReq, name, portReq, valid := util.SplitSchemeNamePort(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 { // Ignore requested scheme, use scheme provided by GetConnectionInfo scheme, port, kubeletTransport, 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), ), }, kubeletTransport, nil } return &url.URL{Scheme: schemeReq, Host: net.JoinHostPort(host, portReq)}, proxyTransport, nil }
// 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 } } } return nil, nil, errors.NewServiceUnavailable(fmt.Sprintf("no endpoints available for service %q", id)) }